/* * Tiny Vector Matrix Library * Dense Vector Matrix Libary of Tiny size using Expression Templates * * Copyright (C) 2001 - 2003 Olaf Petzold * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: NumericTraits.h,v 1.11 2004/11/04 18:10:35 opetzold Exp $ */ #ifndef TVMET_NUMERIC_TRAITS_H #define TVMET_NUMERIC_TRAITS_H #if defined(TVMET_HAVE_COMPLEX) # include #endif #include #include #include namespace tvmet { /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits for integral types for operations. * * For each type we have to specialize this traits. * * \note Keep in mind that the long types long long and long double doesn't * have traits. This is due to the sum_type. We can't give a guarantee * that there is a type of holding the sum. Therefore using this traits * is only safe if you have long long resp. long double types by * working on long ints and doubles. Otherwise you will get not expected * result for some circumstances. Anyway, you can use big integer/float * libraries and specialize the traits by your own. * * \todo The abs function of complex can have an * overrun due to numeric computation. Solve it (someone * using value_type=long here?) */ template struct NumericTraits { typedef T base_type; typedef T value_type; typedef value_type sum_type; typedef value_type diff_type; typedef value_type float_type; typedef value_type signed_type; typedef NumericTraits traits_type; typedef const value_type& argument_type; static inline base_type real(argument_type x); static inline base_type imag(argument_type x); static inline value_type conj(argument_type x); static inline base_type abs(argument_type x); static inline value_type sqrt(argument_type x); static inline base_type norm_1(argument_type x) { return NumericTraits::abs(traits_type::real(x)) + NumericTraits::abs(traits_type::imag(x)); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return std::max(NumericTraits::abs(traits_type::real(x)), NumericTraits::abs(traits_type::imag(x))); } static inline bool equals(argument_type lhs, argument_type rhs) { static base_type sqrt_epsilon( NumericTraits::sqrt( std::numeric_limits::epsilon())); return traits_type::norm_inf(lhs - rhs) < sqrt_epsilon * std::max(std::max(traits_type::norm_inf(lhs), traits_type::norm_inf(rhs)), std::numeric_limits::min()); } }; /* * numeric traits for standard types */ /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for char. */ template<> struct NumericTraits { typedef char value_type; typedef value_type base_type; typedef long sum_type; typedef int diff_type; typedef float float_type; typedef char signed_type; typedef NumericTraits traits_type; typedef value_type argument_type; static inline base_type real(argument_type x) { return x; } static inline base_type imag(argument_type x) { return 0; } static inline value_type conj(argument_type x) { return x; } static inline base_type abs(argument_type x) { return std::abs(x); } static inline value_type sqrt(argument_type x) { return static_cast(std::sqrt(static_cast(x))); } static inline base_type norm_1(argument_type x) { return traits_type::abs(x); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return traits_type::abs(x); } static inline bool equals(argument_type lhs, argument_type rhs) { return lhs == rhs; } enum { is_complex = false }; /** Complexity on operations. */ enum { ops_plus = 1, /**< Complexity on plus/minus ops. */ ops_muls = 1 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for unsigned char. * * \note Normally it doesn't make sense to call conj * for an unsigned type! An unary minus operator * applied to unsigned type will result unsigned. Therefore * this function is missing here. */ template<> struct NumericTraits { typedef unsigned char value_type; typedef value_type base_type; typedef unsigned long sum_type; typedef int diff_type; typedef float float_type; typedef int signed_type; typedef NumericTraits traits_type; typedef value_type argument_type; static inline base_type real(argument_type x) { return x; } static inline base_type imag(argument_type x) { return 0; } static inline base_type abs(argument_type x) { return std::abs(x); } static inline value_type sqrt(argument_type x) { return static_cast(std::sqrt(static_cast(x))); } static inline base_type norm_1(argument_type x) { return traits_type::abs(x); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return traits_type::abs(x); } static inline bool equals(argument_type lhs, argument_type rhs) { return lhs == rhs; } enum { is_complex = false }; /** Complexity on operations. */ enum { ops_plus = 1, /**< Complexity on plus/minus ops. */ ops_muls = 1 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for short int. */ template<> struct NumericTraits { typedef short int value_type; typedef value_type base_type; #if defined(TVMET_HAVE_LONG_LONG) typedef long long sum_type; #else typedef long sum_type; #endif typedef int diff_type; typedef float float_type; typedef short int signed_type; typedef NumericTraits traits_type; typedef value_type argument_type; static inline base_type real(argument_type x) { return x; } static inline base_type imag(argument_type x) { return 0; } static inline value_type conj(argument_type x) { return x; } static inline base_type abs(argument_type x) { return std::abs(x); } static inline value_type sqrt(argument_type x) { return static_cast(std::sqrt(static_cast(x))); } static inline base_type norm_1(argument_type x) { return traits_type::abs(x); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return traits_type::abs(x); } static inline bool equals(argument_type lhs, argument_type rhs) { return lhs == rhs; } enum { is_complex = false }; /** Complexity on operations. */ enum { ops_plus = 1, /**< Complexity on plus/minus ops. */ ops_muls = 1 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for short unsigned int. * * \note Normally it doesn't make sense to call conj * for an unsigned type! An unary minus operator * applied to unsigned type will result unsigned. Therefore * this function is missing here. */ template<> struct NumericTraits { typedef short unsigned int value_type; typedef value_type base_type; #if defined(TVMET_HAVE_LONG_LONG) typedef unsigned long long sum_type; #else typedef unsigned long sum_type; #endif typedef int diff_type; typedef float float_type; typedef int signed_type; typedef NumericTraits traits_type; typedef value_type argument_type; static inline base_type real(argument_type x) { return x; } static inline base_type imag(argument_type x) { return 0; } static inline base_type abs(argument_type x) { return std::abs(x); } static inline value_type sqrt(argument_type x) { return static_cast(std::sqrt(static_cast(x))); } static inline base_type norm_1(argument_type x) { return traits_type::abs(x); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return traits_type::abs(x); } static inline bool equals(argument_type lhs, argument_type rhs) { return lhs == rhs; } enum { is_complex = false }; /** Complexity on operations. */ enum { ops_plus = 1, /**< Complexity on plus/minus ops. */ ops_muls = 1 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for int. */ template<> struct NumericTraits { typedef int value_type; typedef value_type base_type; #if defined(TVMET_HAVE_LONG_LONG) typedef long long sum_type; #else typedef long sum_type; #endif typedef int diff_type; typedef double float_type; typedef int signed_type; typedef NumericTraits traits_type; typedef value_type argument_type; static inline base_type real(argument_type x) { return x; } static inline base_type imag(argument_type x) { return 0; } static inline value_type conj(argument_type x) { return x; } static inline base_type abs(argument_type x) { return std::abs(x); } static inline value_type sqrt(argument_type x) { return static_cast(std::sqrt(static_cast(x))); } static inline base_type norm_1(argument_type x) { return traits_type::abs(x); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return traits_type::abs(x); } static inline bool equals(argument_type lhs, argument_type rhs) { return lhs == rhs; } enum { is_complex = false }; /** Complexity on operations. */ enum { ops_plus = 1, /**< Complexity on plus/minus ops. */ ops_muls = 1 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for unsigned int. * * \note Normally it doesn't make sense to call conj * for an unsigned type! An unary minus operator * applied to unsigned type will result unsigned. Therefore * this function is missing here. */ template<> struct NumericTraits { typedef unsigned int value_type; typedef value_type base_type; #if defined(TVMET_HAVE_LONG_LONG) typedef unsigned long long sum_type; #else typedef unsigned long sum_type; #endif typedef int diff_type; typedef double float_type; typedef long signed_type; typedef NumericTraits traits_type; typedef value_type argument_type; static inline base_type real(argument_type x) { return x; } static inline base_type imag(argument_type x) { return 0; } static inline base_type abs(argument_type x) { return x; } static inline value_type sqrt(argument_type x) { return static_cast(std::sqrt(static_cast(x))); } static inline base_type norm_1(argument_type x) { return traits_type::abs(x); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return traits_type::abs(x); } static inline bool equals(argument_type lhs, argument_type rhs) { return lhs == rhs; } enum { is_complex = false }; /** Complexity on operations. */ enum { ops_plus = 1, /**< Complexity on plus/minus ops. */ ops_muls = 1 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for long. */ template<> struct NumericTraits { typedef long value_type; typedef value_type base_type; #if defined(TVMET_HAVE_LONG_LONG) typedef long long sum_type; #else typedef long sum_type; #endif typedef long diff_type; typedef double float_type; typedef long signed_type; typedef NumericTraits traits_type; typedef value_type argument_type; static inline base_type real(argument_type x) { return x; } static inline base_type imag(argument_type x) { return 0; } static inline value_type conj(argument_type x) { return x; } static inline base_type abs(argument_type x) { return std::abs(x); } static inline value_type sqrt(argument_type x) { return static_cast(std::sqrt(static_cast(x))); } static inline base_type norm_1(argument_type x) { return traits_type::abs(x); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return traits_type::abs(x); } static inline bool equals(argument_type lhs, argument_type rhs) { return lhs == rhs; } enum { is_complex = false }; /** Complexity on operations. */ enum { ops_plus = 1, /**< Complexity on plus/minus ops. */ ops_muls = 1 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for unsigned long. * * \note Normally it doesn't make sense to call conj * for an unsigned type! An unary minus operator * applied to unsigned type will result unsigned. Therefore * this function is missing here. */ template<> struct NumericTraits { typedef unsigned long value_type; typedef value_type base_type; #if defined(TVMET_HAVE_LONG_LONG) typedef unsigned long long sum_type; #else typedef unsigned long sum_type; #endif typedef unsigned long diff_type; typedef double float_type; typedef long signed_type; typedef NumericTraits traits_type; typedef value_type argument_type; static inline base_type real(argument_type x) { return x; } static inline base_type imag(argument_type x) { return 0; } static inline base_type abs(argument_type x) { return x; } static inline value_type sqrt(argument_type x) { return static_cast(std::sqrt(static_cast(x))); } static inline base_type norm_1(argument_type x) { return traits_type::abs(x); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return traits_type::abs(x); } static inline bool equals(argument_type lhs, argument_type rhs) { return lhs == rhs; } enum { is_complex = false }; /** Complexity on operations. */ enum { ops_plus = 1, /**< Complexity on plus/minus ops. */ ops_muls = 1 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for float. */ template<> struct NumericTraits { typedef float value_type; typedef value_type base_type; typedef double sum_type; typedef float diff_type; typedef float float_type; typedef float signed_type; typedef NumericTraits traits_type; typedef value_type argument_type; static inline base_type real(argument_type x) { return x; } static inline base_type imag(argument_type x) { return 0; } static inline value_type conj(argument_type x) { return x; } static inline base_type abs(argument_type x) { return std::abs(x); } static inline value_type sqrt(argument_type x) { return std::sqrt(x); } static inline base_type norm_1(argument_type x) { return traits_type::abs(x); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return traits_type::abs(x); } static inline bool equals(argument_type lhs, argument_type rhs) { static base_type sqrt_epsilon( NumericTraits::sqrt( std::numeric_limits::epsilon())); return traits_type::norm_inf(lhs - rhs) < sqrt_epsilon * std::max(std::max(traits_type::norm_inf(lhs), traits_type::norm_inf(rhs)), std::numeric_limits::min()); } enum { is_complex = false }; /** Complexity on operations. */ enum { ops_plus = 1, /**< Complexity on plus/minus ops. */ ops_muls = 1 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for double. */ template<> struct NumericTraits { typedef double value_type; typedef value_type base_type; #if defined(TVMET_HAVE_LONG_DOUBLE) typedef long double sum_type; #else typedef double sum_type; #endif typedef double diff_type; typedef double float_type; typedef double signed_type; typedef NumericTraits traits_type; typedef value_type argument_type; static inline base_type real(argument_type x) { return x; } static inline base_type imag(argument_type x) { return 0; } static inline value_type conj(argument_type x) { return x; } static inline base_type abs(argument_type x) { return std::abs(x); } static inline value_type sqrt(argument_type x) { return std::sqrt(x); } static inline base_type norm_1(argument_type x) { return traits_type::abs(x); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return traits_type::abs(x); } static inline bool equals(argument_type lhs, argument_type rhs) { static base_type sqrt_epsilon( NumericTraits::sqrt( std::numeric_limits::epsilon())); return traits_type::norm_inf(lhs - rhs) < sqrt_epsilon * std::max(std::max(traits_type::norm_inf(lhs), traits_type::norm_inf(rhs)), std::numeric_limits::min()); } enum { is_complex = false }; /** Complexity on operations. */ enum { ops_plus = 1, /**< Complexity on plus/minus ops. */ ops_muls = 1 /**< Complexity on multiplications. */ }; }; #if defined(TVMET_HAVE_LONG_DOUBLE) /** * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for long double. */ template<> struct NumericTraits { typedef long double value_type; typedef value_type base_type; typedef long double sum_type; typedef long double diff_type; typedef long double float_type; typedef long double signed_type; typedef NumericTraits traits_type; typedef value_type argument_type; static inline base_type real(argument_type x) { return x; } static inline base_type imag(argument_type x) { return 0; } static inline value_type conj(argument_type x) { return x; } static inline base_type abs(argument_type x) { return std::abs(x); } static inline value_type sqrt(argument_type x) { return std::sqrt(x); } static inline base_type norm_1(argument_type x) { return traits_type::abs(x); } static inline base_type norm_2(argument_type x) { return traits_type::abs(x); } static inline base_type norm_inf(argument_type x) { return traits_type::abs(x); } static inline bool equals(argument_type lhs, argument_type rhs) { static base_type sqrt_epsilon( NumericTraits::sqrt( std::numeric_limits::epsilon())); return traits_type::norm_inf(lhs - rhs) < sqrt_epsilon * std::max(std::max(traits_type::norm_inf(lhs), traits_type::norm_inf(rhs)), std::numeric_limits::min()); } enum { is_complex = false }; /** Complexity on operations. */ enum { ops_plus = 1, /**< Complexity on plus/minus ops. */ ops_muls = 1 /**< Complexity on multiplications. */ }; }; #endif // TVMET_HAVE_LONG_DOUBLE /* * numeric traits for complex types */ #if defined(TVMET_HAVE_COMPLEX) /** * \class NumericTraits< std::complex > NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for std::complex. */ template<> struct NumericTraits< std::complex > { typedef int base_type; typedef std::complex value_type; typedef std::complex sum_type; typedef std::complex diff_type; typedef std::complex float_type; typedef std::complex signed_type; typedef NumericTraits traits_type; typedef const value_type& argument_type; static inline base_type real(argument_type z) { return std::real(z); } static inline base_type imag(argument_type z) { return std::imag(z); } static inline value_type conj(argument_type z) { return std::conj(z); } static inline base_type abs(argument_type z) { base_type x = z.real(); base_type y = z.imag(); // XXX probably case of overrun; header complex uses scaling return static_cast(NumericTraits::sqrt(x * x + y * y)); } static /* inline */ value_type sqrt(argument_type z) { // borrowed and adapted from header complex base_type x = z.real(); base_type y = z.imag(); if(x == base_type()) { base_type t = NumericTraits::sqrt( NumericTraits::abs(y) / 2); return value_type(t, y < base_type() ? -t : t); } else { base_type t = NumericTraits::sqrt( 2 * (traits_type::abs(z) + NumericTraits::abs(x))); base_type u = t / 2; return x > base_type() ? value_type(u, y / t) : value_type(NumericTraits::abs(y) / t, y < base_type() ? -u : u); } } static inline base_type norm_1(argument_type z) { return NumericTraits::abs((traits_type::real(z))) + NumericTraits::abs((traits_type::imag(z))); } static inline base_type norm_2(argument_type z) { return traits_type::abs(z); } static inline base_type norm_inf(argument_type z) { return std::max(NumericTraits::abs(traits_type::real(z)), NumericTraits::abs(traits_type::imag(z))); } static inline bool equals(argument_type lhs, argument_type rhs) { return (traits_type::real(lhs) == traits_type::real(rhs)) && (traits_type::imag(lhs) == traits_type::imag(rhs)); } enum { is_complex = true }; /** Complexity on operations. */ enum { ops_plus = 2, /**< Complexity on plus/minus ops. */ ops_muls = 6 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits< std::complex > NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for std::complex. * * \note Normally it doesn't make sense to call conj * for an unsigned type! An unary minus operator * applied to unsigned type will result unsigned. Therefore * this function is missing here. */ template<> struct NumericTraits< std::complex > { typedef unsigned int base_type; typedef std::complex value_type; typedef std::complex sum_type; typedef std::complex diff_type; typedef std::complex float_type; typedef std::complex signed_type; typedef NumericTraits traits_type; typedef const value_type& argument_type; static inline base_type real(argument_type z) { return std::real(z); } static inline base_type imag(argument_type z) { return std::imag(z); } static inline base_type abs(argument_type z) { base_type x = z.real(); base_type y = z.imag(); // XXX probably case of overrun; header complex uses scaling return static_cast(NumericTraits::sqrt(x * x + y * y)); } static /* inline */ value_type sqrt(argument_type z) { // borrowed and adapted from header complex base_type x = z.real(); base_type y = z.imag(); if(x == base_type()) { base_type t = NumericTraits::sqrt( NumericTraits::abs(y) / 2); return value_type(t, t); } else { base_type t = NumericTraits::sqrt( 2 * (traits_type::abs(z) + NumericTraits::abs(x))); return value_type(t / 2, y / t); } } static inline base_type norm_1(argument_type z) { return NumericTraits::abs((traits_type::real(z))) + NumericTraits::abs((traits_type::imag(z))); } static inline base_type norm_2(argument_type z) { return traits_type::abs(z); } static inline base_type norm_inf(argument_type z) { return std::max(NumericTraits::abs(traits_type::real(z)), NumericTraits::abs(traits_type::imag(z))); } static inline bool equals(argument_type lhs, argument_type rhs) { return (traits_type::real(lhs) == traits_type::real(rhs)) && (traits_type::imag(lhs) == traits_type::imag(rhs)); } enum { is_complex = true }; /** Complexity on operations. */ enum { ops_plus = 2, /**< Complexity on plus/minus ops. */ ops_muls = 6 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits< std::complex > NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for std::complex. */ template<> struct NumericTraits< std::complex > { typedef long base_type; typedef std::complex value_type; #if defined(TVMET_HAVE_LONG_LONG) typedef std::complex sum_type; #else typedef std::complex sum_type; #endif typedef std::complex diff_type; typedef std::complex float_type; typedef std::complex signed_type; typedef NumericTraits traits_type; typedef const value_type& argument_type; static inline base_type real(argument_type z) { return std::real(z); } static inline base_type imag(argument_type z) { return std::imag(z); } static inline value_type conj(argument_type z) { return std::conj(z); } static inline base_type abs(argument_type z) { base_type x = z.real(); base_type y = z.imag(); // XXX probably case of overrun; header complex uses scaling return static_cast(NumericTraits::sqrt(x * x + y * y)); } static /* inline */ value_type sqrt(argument_type z) { // borrowed and adapted from header complex base_type x = z.real(); base_type y = z.imag(); if(x == base_type()) { base_type t = NumericTraits::sqrt( NumericTraits::abs(y) / 2); return value_type(t, y < base_type() ? -t : t); } else { base_type t = NumericTraits::sqrt( 2 * (traits_type::abs(z) + NumericTraits::abs(x))); base_type u = t / 2; return x > base_type() ? value_type(u, y / t) : value_type(NumericTraits::abs(y) / t, y < base_type() ? -u : u); } } static inline base_type norm_1(argument_type z) { return NumericTraits::abs((traits_type::real(z))) + NumericTraits::abs((traits_type::imag(z))); } static inline base_type norm_2(argument_type z) { return traits_type::abs(z); } static inline base_type norm_inf(argument_type z) { return std::max(NumericTraits::abs(traits_type::real(z)), NumericTraits::abs(traits_type::imag(z))); } static inline bool equals(argument_type lhs, argument_type rhs) { return (traits_type::real(lhs) == traits_type::real(rhs)) && (traits_type::imag(lhs) == traits_type::imag(rhs)); } enum { is_complex = true }; /** Complexity on operations. */ enum { ops_plus = 2, /**< Complexity on plus/minus ops. */ ops_muls = 6 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits< std::complex > NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for std::complex. * * \note Normally it doesn't make sense to call conj * for an unsigned type! An unary minus operator * applied to unsigned type will result unsigned. Therefore * this function is missing here. */ template<> struct NumericTraits< std::complex > { typedef unsigned long base_type; typedef std::complex value_type; #if defined(TVMET_HAVE_LONG_LONG) typedef std::complex sum_type; #else typedef std::complex sum_type; #endif typedef std::complex diff_type; typedef std::complex float_type; typedef std::complex signed_type; typedef NumericTraits traits_type; typedef const value_type& argument_type; static inline base_type real(argument_type z) { return std::real(z); } static inline base_type imag(argument_type z) { return std::imag(z); } static inline base_type abs(argument_type z) { base_type x = z.real(); base_type y = z.imag(); // XXX probably case of overrun; header complex uses scaling return static_cast(NumericTraits::sqrt(x * x + y * y)); } static /* inline */ value_type sqrt(argument_type z) { // borrowed and adapted from header complex base_type x = z.real(); base_type y = z.imag(); if(x == base_type()) { base_type t = NumericTraits::sqrt( NumericTraits::abs(y) / 2); return value_type(t, t); } else { base_type t = NumericTraits::sqrt( 2 * (traits_type::abs(z) + NumericTraits::abs(x))); return value_type(t / 2, y / t); } } static inline base_type norm_1(argument_type z) { return NumericTraits::abs((traits_type::real(z))) + NumericTraits::abs((traits_type::imag(z))); } static inline base_type norm_2(argument_type z) { return traits_type::abs(z); } static inline base_type norm_inf(argument_type z) { return std::max(NumericTraits::abs(traits_type::real(z)), NumericTraits::abs(traits_type::imag(z))); } static inline bool equals(argument_type lhs, argument_type rhs) { return (traits_type::real(lhs) == traits_type::real(rhs)) && (traits_type::imag(lhs) == traits_type::imag(rhs)); } enum { is_complex = true }; /** Complexity on operations.*/ enum { ops_plus = 2, /**< Complexity on plus/minus ops. */ ops_muls = 6 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits< std::complex > NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for std::complex. */ template<> struct NumericTraits< std::complex > { typedef float base_type; typedef std::complex value_type; typedef std::complex sum_type; typedef std::complex diff_type; typedef std::complex float_type; typedef std::complex signed_type; typedef NumericTraits traits_type; typedef const value_type& argument_type; static inline base_type real(argument_type z) { return std::real(z); } static inline base_type imag(argument_type z) { return std::imag(z); } static inline value_type conj(argument_type z) { return std::conj(z); } static inline base_type abs(argument_type z) { return std::abs(z); } static inline value_type sqrt(argument_type z) { return std::sqrt(z); } static inline base_type norm_1(argument_type z) { return NumericTraits::abs((traits_type::real(z))) + NumericTraits::abs((traits_type::imag(z))); } static inline base_type norm_2(argument_type z) { return traits_type::abs(z); } static inline base_type norm_inf(argument_type z) { return std::max(NumericTraits::abs(traits_type::real(z)), NumericTraits::abs(traits_type::imag(z))); } static inline bool equals(argument_type lhs, argument_type rhs) { static base_type sqrt_epsilon( NumericTraits::sqrt( std::numeric_limits::epsilon())); return traits_type::norm_inf(lhs - rhs) < sqrt_epsilon * std::max(std::max(traits_type::norm_inf(lhs), traits_type::norm_inf(rhs)), std::numeric_limits::min()); } enum { is_complex = true }; /** Complexity on operations. */ enum { ops_plus = 2, /**< Complexity on plus/minus ops. */ ops_muls = 6 /**< Complexity on multiplications. */ }; }; /** * \class NumericTraits< std::complex > NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for std::complex. */ template<> struct NumericTraits< std::complex > { typedef double base_type; typedef std::complex value_type; #if defined(TVMET_HAVE_LONG_DOUBLE) typedef std::complex sum_type; #else typedef std::complex sum_type; #endif typedef std::complex diff_type; typedef std::complex float_type; typedef std::complex signed_type; typedef NumericTraits traits_type; typedef const value_type& argument_type; static inline base_type real(argument_type z) { return std::real(z); } static inline base_type imag(argument_type z) { return std::imag(z); } static inline value_type conj(argument_type z) { return std::conj(z); } static inline base_type abs(argument_type z) { return std::abs(z); } static inline value_type sqrt(argument_type z) { return std::sqrt(z); } static inline base_type norm_1(argument_type z) { return NumericTraits::abs((traits_type::real(z))) + NumericTraits::abs((traits_type::imag(z))); } static inline base_type norm_2(argument_type z) { return traits_type::abs(z); } static inline base_type norm_inf(argument_type z) { return std::max(NumericTraits::abs(traits_type::real(z)), NumericTraits::abs(traits_type::imag(z))); } static inline bool equals(argument_type lhs, argument_type rhs) { static base_type sqrt_epsilon( NumericTraits::sqrt( std::numeric_limits::epsilon())); return traits_type::norm_inf(lhs - rhs) < sqrt_epsilon * std::max(std::max(traits_type::norm_inf(lhs), traits_type::norm_inf(rhs)), std::numeric_limits::min()); } enum { is_complex = true }; /** Complexity on operations. */ enum { ops_plus = 2, /**< Complexity on plus/minus ops. */ ops_muls = 6 /**< Complexity on multiplications. */ }; }; #if defined(TVMET_HAVE_LONG_DOUBLE) /** * \class NumericTraits< std::complex > NumericTraits.h "tvmet/NumericTraits.h" * \brief Traits specialized for std::complex. */ template<> struct NumericTraits< std::complex > { typedef long double base_type; typedef std::complex value_type; typedef std::complex sum_type; typedef std::complex diff_type; typedef std::complex float_type; typedef std::complex signed_type; typedef NumericTraits traits_type; typedef const value_type& argument_type; static inline base_type real(argument_type z) { return std::real(z); } static inline base_type imag(argument_type z) { return std::imag(z); } static inline value_type conj(argument_type z) { return std::conj(z); } static inline base_type abs(argument_type z) { return std::abs(z); } static inline value_type sqrt(argument_type z) { return std::sqrt(z); } static inline base_type norm_1(argument_type z) { return NumericTraits::abs((traits_type::real(z))) + NumericTraits::abs((traits_type::imag(z))); } static inline base_type norm_2(argument_type z) { return traits_type::abs(z); } static inline base_type norm_inf(argument_type z) { return std::max(NumericTraits::abs(traits_type::real(z)), NumericTraits::abs(traits_type::imag(z))); } static inline bool equals(argument_type lhs, argument_type rhs) { static base_type sqrt_epsilon( NumericTraits::sqrt( std::numeric_limits::epsilon())); return traits_type::norm_inf(lhs - rhs) < sqrt_epsilon * std::max(std::max(traits_type::norm_inf(lhs), traits_type::norm_inf(rhs)), std::numeric_limits::min()); } enum { is_complex = true }; /** Complexity on operations. */ enum { ops_plus = 2, /**< Complexity on plus/minus ops. */ ops_muls = 6 /**< Complexity on multiplications. */ }; }; #endif // defined(TVMET_HAVE_LONG_DOUBLE) #endif // defined(TVMET_HAVE_COMPLEX) } // namespace tvmet #endif // TVMET_NUMERIC_TRAITS_H // Local Variables: // mode:C++ // End: