Teuchos_ScalarTraits.hpp

Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //                    Teuchos: Common Tools Package
00005 //                 Copyright (2004) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 // Kris
00030 // 06.18.03 -- Minor formatting changes
00031 //          -- Changed calls to LAPACK objects to use new <OType, SType> templates
00032 // 07.08.03 -- Move into Teuchos package/namespace
00033 // 07.11.03 -- Added ScalarTraits for ARPREC::mp_real
00034 // 07.14.03 -- Fixed int rand() function (was set up to return a floating-point style random number)
00035 // 07.17.03 -- Added squareroot() function
00036 
00037 #ifndef _TEUCHOS_SCALARTRAITS_HPP_
00038 #define _TEUCHOS_SCALARTRAITS_HPP_
00039 
00044 #include "Teuchos_ConfigDefs.hpp"
00045 
00046 #ifndef HAVE_NUMERIC_LIMITS
00047 #include "Teuchos_LAPACK.hpp"
00048 #endif
00049 
00050 #ifdef HAVE_TEUCHOS_ARPREC
00051 #include "mp/mpreal.h"
00052 #endif
00053 
00054 #ifdef HAVE_TEUCHOS_GNU_MP
00055 #include "gmp.h"
00056 #include "gmpxx.h"
00057 #endif
00058 
00081 /* This is the default structure used by ScalarTraits<T> to produce a compile time
00082   error when the specialization does not exist for type <tt>T</tt>.
00083 */
00084 namespace Teuchos {
00085   template<class T>
00086   struct UndefinedScalarTraits
00087   {
00089     static inline T notDefined() { return T::this_type_is_missing_a_specialization(); };
00090   };
00091 
00092   template<class T>
00093   struct ScalarTraits
00094   {
00096     typedef T magnitudeType;
00098     static const bool isComplex = false;
00100     static const bool isComparable = false;
00102     static const bool hasMachineParameters = false;
00104     static inline magnitudeType eps()   { return UndefinedScalarTraits<T>::notDefined(); };
00106     static inline magnitudeType sfmin() { return UndefinedScalarTraits<T>::notDefined(); };
00108     static inline magnitudeType base()  { return UndefinedScalarTraits<T>::notDefined(); };
00110     static inline magnitudeType prec()  { return UndefinedScalarTraits<T>::notDefined(); };
00112     static inline magnitudeType t()     { return UndefinedScalarTraits<T>::notDefined(); };
00114     static inline magnitudeType rnd()   { return UndefinedScalarTraits<T>::notDefined(); };
00116     static inline magnitudeType emin()  { return UndefinedScalarTraits<T>::notDefined(); };
00118     static inline magnitudeType rmin()  { return UndefinedScalarTraits<T>::notDefined(); };
00120     static inline magnitudeType emax()  { return UndefinedScalarTraits<T>::notDefined(); };
00122     static inline magnitudeType rmax()  { return UndefinedScalarTraits<T>::notDefined(); };
00124     static inline magnitudeType magnitude(T a) { return UndefinedScalarTraits<T>::notDefined(); };
00126     static inline T zero()                     { return UndefinedScalarTraits<T>::notDefined(); };
00128     static inline T one()                      { return UndefinedScalarTraits<T>::notDefined(); };
00130     static inline T conjugate(T a) { return UndefinedScalarTraits<T>::notDefined(); };
00132     static inline T nan()                      { return UndefinedScalarTraits<T>::notDefined(); };
00134     static inline bool isnaninf(const T& x)     { return UndefinedScalarTraits<T>::notDefined(); };
00136     static inline void seedrandom(unsigned int s) { int i; T t = &i; };
00138     static inline T random()                   { return UndefinedScalarTraits<T>::notDefined(); };
00140     static inline std::string name()           { (void)UndefinedScalarTraits<T>::notDefined(); return 0; };
00142     static inline magnitudeType squareroot(T x) { return UndefinedScalarTraits<T>::notDefined(); };
00143   };
00144   
00145 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00146 
00147   template<>
00148   struct ScalarTraits<int>
00149   {
00150     typedef int magnitudeType;
00151     static const bool isComplex = false;
00152     static const bool isComparable = true;
00153     static const bool hasMachineParameters = false;
00154     // Not defined: eps(), sfmin(), base(), prec(), t(), rnd(), emin(), rmin(), emax(), rmax()
00155     static inline magnitudeType magnitude(int a) { return ::abs(a); };
00156     static inline int zero()  { return 0; };
00157     static inline int one()   { return 1; };
00158     static inline int conjugate(int x) { return x; };
00159     static inline void seedrandom(unsigned int s) { srand(s); };
00160     //static inline int random() { return (-1 + 2*rand()); };  // RAB: This version should be used to be consistent with others
00161     static inline int random() { return rand(); };             // RAB: This version should be used for an unsigned int, not int
00162     static inline std::string name() { return "int"; };
00163     static inline int squareroot(int x) { return (int) ::sqrt((double) x); };
00164   };
00165 
00166 #ifndef __sun
00167   extern const float flt_nan;
00168 #endif
00169  
00170   template<>
00171   struct ScalarTraits<float>
00172   {
00173     typedef float magnitudeType;
00174     static const bool isComplex = false;
00175     static const bool isComparable = true;
00176     static const bool hasMachineParameters = true;
00177     static inline float eps()   {
00178 #ifdef HAVE_NUMERIC_LIMITS
00179       return std::numeric_limits<float>::epsilon();
00180 #else
00181       LAPACK<int, float> lp; return lp.LAMCH('E');
00182 #endif
00183     }
00184     static inline float sfmin() {
00185 #ifdef HAVE_NUMERIC_LIMITS
00186       return std::numeric_limits<float>::min();
00187 #else
00188       LAPACK<int, float> lp; return lp.LAMCH('S');
00189 #endif
00190     };
00191     static inline float base()  {
00192 #ifdef HAVE_NUMERIC_LIMITS
00193       return std::numeric_limits<float>::radix;
00194 #else
00195       LAPACK<int, float> lp; return lp.LAMCH('B');
00196 #endif
00197     };
00198     static inline float prec()  {
00199 #ifdef HAVE_NUMERIC_LIMITS
00200       return eps()*base();
00201 #else
00202       LAPACK<int, float> lp; return lp.LAMCH('P');
00203 #endif
00204     };
00205     static inline float t()     {
00206 #ifdef HAVE_NUMERIC_LIMITS
00207       return std::numeric_limits<float>::digits;
00208 #else
00209       LAPACK<int, float> lp; return lp.LAMCH('N');
00210 #endif
00211     };
00212     static inline float rnd()   {
00213 #ifdef HAVE_NUMERIC_LIMITS
00214       return ( std::numeric_limits<float>::round_style == std::round_to_nearest ? float(1.0) : float(0.0) );
00215 #else
00216       LAPACK<int, float> lp; return lp.LAMCH('R');
00217 #endif
00218     };
00219     static inline float emin()  {
00220 #ifdef HAVE_NUMERIC_LIMITS
00221       return std::numeric_limits<float>::min_exponent;
00222 #else
00223       LAPACK<int, float> lp; return lp.LAMCH('M');
00224 #endif
00225     };
00226     static inline float rmin()  {
00227 #ifdef HAVE_NUMERIC_LIMITS
00228       return std::numeric_limits<float>::min();
00229 #else
00230       LAPACK<int, float> lp; return lp.LAMCH('U');
00231 #endif
00232     };
00233     static inline float emax()  {
00234 #ifdef HAVE_NUMERIC_LIMITS
00235       return std::numeric_limits<float>::max_exponent;
00236 #else
00237       LAPACK<int, float> lp; return lp.LAMCH('L');
00238 #endif
00239     };
00240     static inline float rmax()  {
00241 #ifdef HAVE_NUMERIC_LIMITS
00242       return std::numeric_limits<float>::max();
00243 #else
00244       LAPACK<int, float> lp; return lp.LAMCH('O');
00245 #endif
00246     };
00247     static inline magnitudeType magnitude(float a) { return fabs(a); };    
00248     static inline float zero()  { return(0.0); };
00249     static inline float one()   { return(1.0); };    
00250     static inline float conjugate(float x)   { return(x); };    
00251     static inline float nan() {
00252 #ifdef __sun
00253       return 0.0/sin(0.0);
00254 #else
00255       return flt_nan;
00256 #endif
00257     };
00258     static inline bool isnaninf(float x) { // RAB: 2004/05/28: Taken from NOX_StatusTest_FiniteValue.C
00259       const float tol = 1e-6; // Any (bounded) number should do!
00260       if( !(x <= tol) && !(x > tol) ) return true;                 // IEEE says this should fail for NaN
00261       float z=0.0*x; if( !(z <= tol) && !(z > tol) ) return true;  // Use fact that Inf*0 = NaN
00262       return false;
00263     }
00264     static inline void seedrandom(unsigned int s) { srand(s); };
00265     static inline float random() { float rnd = (float) rand() / RAND_MAX; return (float)(-1.0 + 2.0 * rnd); };
00266     static inline std::string name() { return "float"; };
00267     static inline float squareroot(float x) { return sqrt(x); };
00268   };
00269 
00270 #ifndef __sun
00271   extern const double dbl_nan;
00272 #endif
00273  
00274   template<>
00275   struct ScalarTraits<double>
00276   {
00277     typedef double magnitudeType;
00278     static const bool isComplex = false;
00279     static const bool isComparable = true;
00280     static const bool hasMachineParameters = true;
00281     static inline double eps()   {
00282 #ifdef HAVE_NUMERIC_LIMITS
00283       return std::numeric_limits<double>::epsilon();
00284 #else
00285       LAPACK<int, double> lp; return lp.LAMCH('E');
00286 #endif
00287     }
00288     static inline double sfmin() {
00289 #ifdef HAVE_NUMERIC_LIMITS
00290       return std::numeric_limits<double>::min();
00291 #else
00292       LAPACK<int, double> lp; return lp.LAMCH('S');
00293 #endif
00294     };
00295     static inline double base()  {
00296 #ifdef HAVE_NUMERIC_LIMITS
00297       return std::numeric_limits<double>::radix;
00298 #else
00299       LAPACK<int, double> lp; return lp.LAMCH('B');
00300 #endif
00301     };
00302     static inline double prec()  {
00303 #ifdef HAVE_NUMERIC_LIMITS
00304       return eps()*base();
00305 #else
00306       LAPACK<int, double> lp; return lp.LAMCH('P');
00307 #endif
00308     };
00309     static inline double t()     {
00310 #ifdef HAVE_NUMERIC_LIMITS
00311       return std::numeric_limits<double>::digits;
00312 #else
00313       LAPACK<int, double> lp; return lp.LAMCH('N');
00314 #endif
00315     };
00316     static inline double rnd()   {
00317 #ifdef HAVE_NUMERIC_LIMITS
00318       return ( std::numeric_limits<double>::round_style == std::round_to_nearest ? double(1.0) : double(0.0) );
00319 #else
00320       LAPACK<int, double> lp; return lp.LAMCH('R');
00321 #endif
00322     };
00323     static inline double emin()  {
00324 #ifdef HAVE_NUMERIC_LIMITS
00325       return std::numeric_limits<double>::min_exponent;
00326 #else
00327       LAPACK<int, double> lp; return lp.LAMCH('M');
00328 #endif
00329     };
00330     static inline double rmin()  {
00331 #ifdef HAVE_NUMERIC_LIMITS
00332       return std::numeric_limits<double>::min();
00333 #else
00334       LAPACK<int, double> lp; return lp.LAMCH('U');
00335 #endif
00336     };
00337     static inline double emax()  {
00338 #ifdef HAVE_NUMERIC_LIMITS
00339       return std::numeric_limits<double>::max_exponent;
00340 #else
00341       LAPACK<int, double> lp; return lp.LAMCH('L');
00342 #endif
00343     };
00344     static inline double rmax()  {
00345 #ifdef HAVE_NUMERIC_LIMITS
00346       return std::numeric_limits<double>::max();
00347 #else
00348       LAPACK<int, double> lp; return lp.LAMCH('O');
00349 #endif
00350     };
00351     static inline magnitudeType magnitude(double a) { return fabs(a); };
00352     static inline double zero()  { return 0.0; };
00353     static inline double one()   { return 1.0; };
00354     static inline double conjugate(double x)   { return(x); };    
00355     static inline double nan() {
00356 #ifdef __sun
00357       return 0.0/sin(0.0);
00358 #else
00359       return dbl_nan;
00360 #endif
00361     };
00362     static inline bool isnaninf(double x) { // RAB: 2004/05/28: Taken from NOX_StatusTest_FiniteValue.C
00363       const double tol = 1e-6; // Any (bounded) number should do!
00364       if( !(x <= tol) && !(x > tol) ) return true;                  // IEEE says this should fail for NaN
00365       double z=0.0*x; if( !(z <= tol) && !(z > tol) ) return true;  // Use fact that Inf*0 = NaN
00366       return false;
00367     }
00368     static inline void seedrandom(unsigned int s) { srand(s); };
00369     static inline double random() { double rnd = (double) rand() / RAND_MAX; return (double)(-1.0 + 2.0 * rnd); };
00370     static inline std::string name() { return "double"; };
00371     static inline double squareroot(double x) { return ::sqrt(x); };
00372   };
00373 
00374 #ifdef HAVE_TEUCHOS_GNU_MP
00375 
00376   extern gmp_randclass gmp_rng; 
00377 
00378   template<>
00379   struct ScalarTraits<mpf_class>
00380   {
00381     typedef mpf_class magnitudeType;
00382     static const bool isComplex = false;
00383     static const bool isComparable = true;
00384     static const bool hasMachineParameters = false;
00385     // Not defined: eps(), sfmin(), base(), prec(), t(), rnd(), emin(), rmin(), emax(), rmax()
00386     static magnitudeType magnitude(mpf_class a) { return abs(a); };
00387     static inline mpf_class zero() { mpf_class zero = 0.0; return zero; };
00388     static inline mpf_class one() { mpf_class one = 1.0; return one; };    
00389     static inline mpf_class conjugate(mpf_class x) { return x; };
00390     static inline bool isnaninf(mpf_class x) { return false; } // mpf_class currently can't handle nan or inf!
00391     static inline void seedrandom(unsigned int s) { 
00392       unsigned long int seedVal = static_cast<unsigned long int>(s);
00393       gmp_rng.seed( seedVal );  
00394     };
00395     static inline mpf_class random() { 
00396       return gmp_rng.get_f(); 
00397     };
00398     static inline std::string name() { return "mpf_class"; };
00399     static inline mpf_class squareroot(mpf_class x) { return sqrt(x); };
00400     // Todo: RAB: 2004/05/28: Add nan() and isnaninf() functions when needed!
00401   };
00402 
00403 #endif  
00404 
00405 #ifdef HAVE_TEUCHOS_ARPREC
00406 
00407   template<>
00408   struct ScalarTraits<mp_real>
00409   {
00410     typedef mp_real magnitudeType;
00411     static const bool isComplex = false;
00412     static const bool isComparable = true;
00413     static const bool hasMachineParameters = false;
00414     // Not defined: eps(), sfmin(), base(), prec(), t(), rnd(), emin(), rmin(), emax(), rmax()
00415     static magnitudeType magnitude(mp_real a) { return abs(a); };
00416     static inline mp_real zero() { mp_real zero = 0.0; return zero; };
00417     static inline mp_real one() { mp_real one = 1.0; return one; };    
00418     static inline mp_real conjugate(mp_real x) { return x; };
00419     static inline bool isnaninf(mp_real x) { return false; } // ToDo: Change this?
00420     static inline void seedrandom(unsigned int s) { 
00421       long int seedVal = static_cast<long int>(s);
00422       srand48(seedVal);
00423     };
00424     static inline mp_real random() { return mp_rand(); };
00425     static inline std::string name() { return "mp_real"; };
00426     static inline mp_real squareroot(mp_real x) { return sqrt(x); };
00427     // Todo: RAB: 2004/05/28: Add nan() and isnaninf() functions when needed!
00428   };
00429   
00430 #endif // HAVE_TEUCHOS_ARPREC
00431  
00432 #if ( defined(HAVE_COMPLEX) || defined(HAVE_COMPLEX_H) ) && defined(HAVE_TEUCHOS_COMPLEX)
00433 
00434   // Partial specialization for complex numbers templated on real type T
00435   template<class T> 
00436   struct ScalarTraits<
00437 #if defined(HAVE_COMPLEX)
00438     std::complex<T>
00439 #elif  defined(HAVE_COMPLEX_H)
00440     ::complex<T>
00441 #endif
00442     >
00443   {
00444 #if defined(HAVE_COMPLEX)
00445     typedef std::complex<T>  ComplexT;
00446 #elif  defined(HAVE_COMPLEX_H)
00447     typedef ::complex<T>     ComplexT;
00448 #endif
00449     typedef typename ScalarTraits<T>::magnitudeType magnitudeType;
00450     static const bool isComplex = true;
00451     static const bool isComparable = false;
00452     static const bool hasMachineParameters = true;
00453     static inline magnitudeType eps()          { return ScalarTraits<magnitudeType>::eps(); };
00454     static inline magnitudeType sfmin()        { return ScalarTraits<magnitudeType>::sfmin(); };
00455     static inline magnitudeType base()         { return ScalarTraits<magnitudeType>::base(); };
00456     static inline magnitudeType prec()         { return ScalarTraits<magnitudeType>::prec(); };
00457     static inline magnitudeType t()            { return ScalarTraits<magnitudeType>::t(); };
00458     static inline magnitudeType rnd()          { return ScalarTraits<magnitudeType>::rnd(); };
00459     static inline magnitudeType emin()         { return ScalarTraits<magnitudeType>::emin(); };
00460     static inline magnitudeType rmin()         { return ScalarTraits<magnitudeType>::rmin(); };
00461     static inline magnitudeType emax()         { return ScalarTraits<magnitudeType>::emax(); };
00462     static inline magnitudeType rmax()         { return ScalarTraits<magnitudeType>::rmax(); };
00463     static magnitudeType magnitude(ComplexT a) { return std::abs(a); };
00464     static inline ComplexT zero()              { return ComplexT(ScalarTraits<magnitudeType>::zero(),ScalarTraits<magnitudeType>::zero()); };
00465     static inline ComplexT one()               { return ComplexT(ScalarTraits<magnitudeType>::one(),ScalarTraits<magnitudeType>::zero()); };
00466     static inline ComplexT conjugate(ComplexT a){ return ComplexT(a.real(),-a.imag()); };
00467     static inline ComplexT nan()               { return ComplexT(ScalarTraits<magnitudeType>::nan(),ScalarTraits<magnitudeType>::nan()); };
00468     static inline bool isnaninf(ComplexT x)    { return ScalarTraits<magnitudeType>::isnaninf(x.real()) || ScalarTraits<magnitudeType>::isnaninf(x.imag()); };
00469     static inline void seedrandom(unsigned int s) { ScalarTraits<magnitudeType>::seedrandom(s); };
00470     static inline ComplexT random()
00471     {
00472       const T rnd1 = ScalarTraits<magnitudeType>::random();
00473       const T rnd2 = ScalarTraits<magnitudeType>::random();
00474       return ComplexT(rnd1,rnd2);
00475     };
00476     static inline std::string name() { return std::string("std::complex<")+std::string(ScalarTraits<magnitudeType>::name())+std::string(">"); };
00477     // This will only return one of the square roots of x, the other can be obtained by taking its conjugate
00478     static inline ComplexT squareroot(ComplexT x)
00479     {
00480       typedef ScalarTraits<magnitudeType>  STMT;
00481       const T r  = x.real(), i = x.imag();
00482       const T a  = STMT::squareroot((r*r)+(i*i));
00483       const T nr = STMT::squareroot((a+r)/2);
00484       const T ni = STMT::squareroot((a-r)/2);
00485       return ComplexT(nr,ni);
00486     };
00487   };
00488 
00489 #endif //  HAVE_COMPLEX || HAVE_COMPLEX_H
00490 
00491 #endif // DOXYGEN_SHOULD_SKIP_THIS
00492 
00493 } // Teuchos namespace
00494 
00495 #endif // _TEUCHOS_SCALARTRAITS_HPP_

Generated on Thu Sep 18 12:39:10 2008 for Teuchos - Trilinos Tools Package by doxygen 1.3.9.1