Eurobot2012_Primary

Dependencies:   mbed Eurobot_2012_Primary

tvmet/NumericTraits.h

Committer:
narshu
Date:
2012-10-17
Revision:
26:0995f61cb7b8
Parent:
25:143b19c1fb05

File content as of revision 26:0995f61cb7b8:

/*
 * Tiny Vector Matrix Library
 * Dense Vector Matrix Libary of Tiny size using Expression Templates
 *
 * Copyright (C) 2001 - 2007 Olaf Petzold <opetzold@users.sourceforge.net>
 *
 * 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.16 2007-06-23 15:58:58 opetzold Exp $
 */

#ifndef TVMET_NUMERIC_TRAITS_H
#define TVMET_NUMERIC_TRAITS_H

#if defined(TVMET_HAVE_COMPLEX)
#  include <complex>
#endif
#include <cmath>
#include <limits>

#include <tvmet/CompileTimeError.h>


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<non_float_type> can have an
 *       overrun due to numeric computation. Solve it (someone
 *       using value_type=long here?)
 */
template<class T>
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<value_type>		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<base_type>::abs(traits_type::real(x))
         + NumericTraits<base_type>::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<base_type>::abs(traits_type::real(x)),
		    NumericTraits<base_type>::abs(traits_type::imag(x)));
   }

  static inline
  bool equals(argument_type lhs, argument_type rhs) {
    static base_type sqrt_epsilon(
      NumericTraits<base_type>::sqrt(
        std::numeric_limits<base_type>::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<base_type>::min());
  }
};


/*
 * numeric traits for standard types
 */


/**
 * \class NumericTraits<char> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for char.
 */
template<>
struct NumericTraits<char> {
  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<value_type>		traits_type;
  typedef value_type				argument_type;

  static inline
  base_type real(argument_type x) { return x; }

  static inline
  base_type imag(argument_type) { 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<value_type>(std::sqrt(static_cast<float_type>(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<unsigned char> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for unsigned char.
 *
 * \note Normally it doesn't make sense to call <tt>conj</tt>
 *       for an unsigned type! An unary minus operator
 *       applied to unsigned type will result unsigned. Therefore
 *       this function is missing here.
 */
template<>
struct NumericTraits<unsigned char> {
  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<value_type>		traits_type;
  typedef value_type				argument_type;

  static inline
  base_type real(argument_type x) { return x; }

  static inline
  base_type imag(argument_type) { 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<value_type>(std::sqrt(static_cast<float_type>(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<short int> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for short int.
 */
template<>
struct NumericTraits<short int> {
  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<value_type>		traits_type;
  typedef value_type				argument_type;

  static inline
  base_type real(argument_type x) { return x; }

  static inline
  base_type imag(argument_type) { 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<value_type>(std::sqrt(static_cast<float_type>(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<short unsigned int> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for short unsigned int.
 *
 * \note Normally it doesn't make sense to call <tt>conj</tt>
 *       for an unsigned type! An unary minus operator
 *       applied to unsigned type will result unsigned. Therefore
 *       this function is missing here.
 */
template<>
struct NumericTraits<short unsigned int> {
  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<value_type>		traits_type;
  typedef value_type				argument_type;

  static inline
  base_type real(argument_type x) { return x; }

  static inline
  base_type imag(argument_type) { 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<value_type>(std::sqrt(static_cast<float_type>(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<int> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for int.
 */
template<>
struct NumericTraits<int> {
  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<value_type>		traits_type;
  typedef value_type				argument_type;

  static inline
  base_type real(argument_type x) { return x; }

  static inline
  base_type imag(argument_type) { 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<value_type>(std::sqrt(static_cast<float_type>(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<unsigned int> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for unsigned int.
 *
 * \note Normally it doesn't make sense to call <tt>conj</tt>
 *       for an unsigned type! An unary minus operator
 *       applied to unsigned type will result unsigned. Therefore
 *       this function is missing here.
 */
template<>
struct NumericTraits<unsigned int> {
  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<value_type>		traits_type;
  typedef value_type				argument_type;

  static inline
  base_type real(argument_type x) { return x; }

  static inline
  base_type imag(argument_type) { return 0; }

  static inline
  base_type abs(argument_type x) { return x; }

  static inline
  value_type sqrt(argument_type x) {
    return static_cast<value_type>(std::sqrt(static_cast<float_type>(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<long> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for long.
 */
template<>
struct NumericTraits<long> {
  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<value_type>		traits_type;
  typedef value_type				argument_type;

  static inline
  base_type real(argument_type x) { return x; }

  static inline
  base_type imag(argument_type) { 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<value_type>(std::sqrt(static_cast<float_type>(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<unsigned long> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for unsigned long.
 *
 * \note Normally it doesn't make sense to call <tt>conj</tt>
 *       for an unsigned type! An unary minus operator
 *       applied to unsigned type will result unsigned. Therefore
 *       this function is missing here.
 */
template<>
struct NumericTraits<unsigned long> {
  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<value_type>		traits_type;
  typedef value_type				argument_type;

  static inline
  base_type real(argument_type x) { return x; }

  static inline
  base_type imag(argument_type) { return 0; }

  static inline
  base_type abs(argument_type x) { return x; }

  static inline
  value_type sqrt(argument_type x) {
    return static_cast<value_type>(std::sqrt(static_cast<float_type>(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<float> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for float.
 */
template<>
struct NumericTraits<float> {
  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<value_type>		traits_type;
  typedef value_type				argument_type;

  static inline
  base_type real(argument_type x) { return x; }

  static inline
  base_type imag(argument_type) { 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<base_type>::sqrt(
        std::numeric_limits<base_type>::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<base_type>::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<double> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for double.
 */
template<>
struct NumericTraits<double> {
  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<value_type>		traits_type;
  typedef value_type				argument_type;

  static inline
  base_type real(argument_type x) { return x; }

  static inline
  base_type imag(argument_type) { 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<base_type>::sqrt(
        std::numeric_limits<base_type>::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<base_type>::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<long double> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for long double.
 */
template<>
struct NumericTraits<long double> {
  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<value_type>		traits_type;
  typedef value_type				argument_type;

  static inline
  base_type real(argument_type x) { return x; }

  static inline
  base_type imag(argument_type) { 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<base_type>::sqrt(
        std::numeric_limits<base_type>::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<base_type>::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<int> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<int>.
 */
template<>
struct NumericTraits< std::complex<int> > {
  typedef int					base_type;
  typedef std::complex<int>			value_type;
  typedef std::complex<long> 			sum_type;
  typedef std::complex<int>			diff_type;
  typedef std::complex<float>			float_type;
  typedef std::complex<int>			signed_type;

  typedef NumericTraits<value_type>		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<base_type>(NumericTraits<base_type>::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<base_type>::sqrt(
                        NumericTraits<base_type>::abs(y) / 2);
	return value_type(t, y < base_type() ? -t : t);
    }
    else {
      base_type t = NumericTraits<base_type>::sqrt(
		      2 * (traits_type::abs(z)
		            + NumericTraits<base_type>::abs(x)));
      base_type u = t / 2;
      return x > base_type()
	? value_type(u, y / t)
	: value_type(NumericTraits<base_type>::abs(y) / t, y < base_type() ? -u : u);
    }
  }

  static inline
  base_type norm_1(argument_type z) {
    return NumericTraits<base_type>::abs((traits_type::real(z)))
         + NumericTraits<base_type>::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<base_type>::abs(traits_type::real(z)),
		    NumericTraits<base_type>::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<unsigned int> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<unsigned int>.
 *
 * \note Normally it doesn't make sense to call <tt>conj</tt>
 *       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<unsigned int> > {
  typedef unsigned int				base_type;
  typedef std::complex<unsigned int> 		value_type;
  typedef std::complex<unsigned long> 		sum_type;
  typedef std::complex<int>			diff_type;
  typedef std::complex<float>			float_type;
  typedef std::complex<int>			signed_type;

  typedef NumericTraits<value_type>		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<base_type>(NumericTraits<base_type>::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<base_type>::sqrt(
                        NumericTraits<base_type>::abs(y) / 2);
	return value_type(t, t);
    }
    else {
      base_type t = NumericTraits<base_type>::sqrt(
		      2 * (traits_type::abs(z)
		            + NumericTraits<base_type>::abs(x)));
      return value_type(t / 2, y / t);
    }
  }

  static inline
  base_type norm_1(argument_type z) {
    return NumericTraits<base_type>::abs((traits_type::real(z)))
         + NumericTraits<base_type>::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<base_type>::abs(traits_type::real(z)),
		    NumericTraits<base_type>::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<long> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<long>.
 */
template<>
struct NumericTraits< std::complex<long> > {
  typedef long					base_type;
  typedef std::complex<long>			value_type;
#if defined(TVMET_HAVE_LONG_LONG)
  typedef std::complex<long long>		sum_type;
#else
  typedef std::complex<long>			sum_type;
#endif
  typedef std::complex<int>			diff_type;
  typedef std::complex<float>			float_type;
  typedef std::complex<int>			signed_type;

  typedef NumericTraits<value_type>		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<base_type>(NumericTraits<base_type>::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<base_type>::sqrt(
                        NumericTraits<base_type>::abs(y) / 2);
	return value_type(t, y < base_type() ? -t : t);
    }
    else {
      base_type t = NumericTraits<base_type>::sqrt(
		      2 * (traits_type::abs(z)
		            + NumericTraits<base_type>::abs(x)));
      base_type u = t / 2;
      return x > base_type()
	? value_type(u, y / t)
	: value_type(NumericTraits<base_type>::abs(y) / t, y < base_type() ? -u : u);
    }
  }

  static inline
  base_type norm_1(argument_type z) {
    return NumericTraits<base_type>::abs((traits_type::real(z)))
         + NumericTraits<base_type>::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<base_type>::abs(traits_type::real(z)),
		    NumericTraits<base_type>::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<unsigned long> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<unsigned long>.
 *
 * \note Normally it doesn't make sense to call <tt>conj</tt>
 *       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<unsigned long> > {
  typedef unsigned long				base_type;
  typedef std::complex<unsigned long>		value_type;
#if defined(TVMET_HAVE_LONG_LONG)
  typedef std::complex<unsigned long long>	sum_type;
#else
  typedef std::complex<unsigned long>		sum_type;
#endif
  typedef std::complex<long>			diff_type;
  typedef std::complex<float>			float_type;
  typedef std::complex<long>			signed_type;

  typedef NumericTraits<value_type>		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<base_type>(NumericTraits<base_type>::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<base_type>::sqrt(
                        NumericTraits<base_type>::abs(y) / 2);
	return value_type(t, t);
    }
    else {
      base_type t = NumericTraits<base_type>::sqrt(
		      2 * (traits_type::abs(z)
		            + NumericTraits<base_type>::abs(x)));
      return value_type(t / 2, y / t);
    }
  }

  static inline
  base_type norm_1(argument_type z) {
    return NumericTraits<base_type>::abs((traits_type::real(z)))
         + NumericTraits<base_type>::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<base_type>::abs(traits_type::real(z)),
		    NumericTraits<base_type>::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<float> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<float>.
 */
template<>
struct NumericTraits< std::complex<float> > {
  typedef float					base_type;
  typedef std::complex<float>			value_type;
  typedef std::complex<double>			sum_type;
  typedef std::complex<float>			diff_type;
  typedef std::complex<float>			float_type;
  typedef std::complex<float>			signed_type;

  typedef NumericTraits<value_type>		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<base_type>::abs((traits_type::real(z)))
         + NumericTraits<base_type>::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<base_type>::abs(traits_type::real(z)),
	            NumericTraits<base_type>::abs(traits_type::imag(z)));
  }

 static inline
  bool equals(argument_type lhs, argument_type rhs) {
    static base_type sqrt_epsilon(
      NumericTraits<base_type>::sqrt(
        std::numeric_limits<base_type>::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<base_type>::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<double> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<double>.
 */
template<>
struct NumericTraits< std::complex<double> > {
  typedef double				base_type;
  typedef std::complex<double>			value_type;
#if defined(TVMET_HAVE_LONG_DOUBLE)
  typedef std::complex<long double> 		sum_type;
#else
  typedef std::complex<double>			sum_type;
#endif
  typedef std::complex<double>			diff_type;
  typedef std::complex<double>			float_type;
  typedef std::complex<double>			signed_type;

  typedef NumericTraits<value_type>		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<base_type>::abs((traits_type::real(z)))
         + NumericTraits<base_type>::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<base_type>::abs(traits_type::real(z)),
	            NumericTraits<base_type>::abs(traits_type::imag(z)));
  }

 static inline
  bool equals(argument_type lhs, argument_type rhs) {
    static base_type sqrt_epsilon(
      NumericTraits<base_type>::sqrt(
        std::numeric_limits<base_type>::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<base_type>::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<long double> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<double>.
 */
template<>
struct NumericTraits< std::complex<long double> > {
  typedef long double				base_type;
  typedef std::complex<long double>		value_type;
  typedef std::complex<long double> 		sum_type;
  typedef std::complex<long double>		diff_type;
  typedef std::complex<long double>		float_type;
  typedef std::complex<long double>		signed_type;

  typedef NumericTraits<value_type>		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<base_type>::abs((traits_type::real(z)))
         + NumericTraits<base_type>::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<base_type>::abs(traits_type::real(z)),
	            NumericTraits<base_type>::abs(traits_type::imag(z)));
  }

  static inline
  bool equals(argument_type lhs, argument_type rhs) {
    static base_type sqrt_epsilon(
      NumericTraits<base_type>::sqrt(
        std::numeric_limits<base_type>::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<base_type>::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++
// tab-width:8
// End: