casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
NumericTraits.h
Go to the documentation of this file.
00001 //# NumericTraits.h: Defines relationships between numeric data types 
00002 //# Copyright (C) 1996,1997,1998,2000,2002
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //#
00005 //# This library is free software; you can redistribute it and/or modify it
00006 //# under the terms of the GNU Library General Public License as published by
00007 //# the Free Software Foundation; either version 2 of the License, or (at your
00008 //# option) any later version.
00009 //#
00010 //# This library is distributed in the hope that it will be useful, but WITHOUT
00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013 //# License for more details.
00014 //#
00015 //# You should have received a copy of the GNU Library General Public License
00016 //# along with this library; if not, write to the Free Software Foundation,
00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00018 //#
00019 //# Correspondence concerning AIPS++ should be addressed as follows:
00020 //#        Internet email: aips2-request@nrao.edu.
00021 //#        Postal address: AIPS++ Project Office
00022 //#                        National Radio Astronomy Observatory
00023 //#                        520 Edgemont Road
00024 //#                        Charlottesville, VA 22903-2475 USA
00025 //#
00026 //# $Id: NumericTraits.h 21024 2011-03-01 11:46:18Z gervandiepen $
00027 
00028 #ifndef SCIMATH_NUMERICTRAITS_H
00029 #define SCIMATH_NUMERICTRAITS_H
00030 
00031 //# Include files
00032 #include <casa/aips.h>
00033 #include <casa/BasicSL/Complex.h>
00034 
00035 namespace casa { //# NAMESPACE CASA - BEGIN
00036 
00037 //
00038 // <summary> Relationships between numeric data types </summary>
00039 // <use visibility=export>
00040 //
00041 // <reviewed reviewer="nkilleen" date="1996/12/12" tests="tConvolver,tFFTServer">
00042 // </reviewed>
00043 //
00044 // <etymology>
00045 // A trait is a characteristic feature. NumericTraits defines relationships
00046 // between and characteristics of Numeric data types.
00047 // </etymology>
00048 //
00049 // <synopsis>
00050 
00051 // This templated class contains a number of typedefs and definitions that
00052 // describe the relationship between different numeric data types and there
00053 // characteristics. Its use is in templated classes either where the use of one
00054 // type implictly implies the use of a corresponding one or where a
00055 // characteristic value differs with templating argument.  Use of this class
00056 // often avoids the need for double templating.
00057 //
00058 // Currently this class defines the following relationships:
00059 // <dl> 
00060 // <dt> <src>value_type</src>
00061 // <dd> The template type itself. The name <src>value_type</src> is the
00062 //      C++ standard (e.g. <src>DComplex::value_type</src> equals
00063 //      <src>double</src>)
00064 // <dt> <src>BaseType</src>
00065 // <dd> The numeric base type. I.e. <src>Double</src> for <src>Double</src>
00066 //      and <src>DComplex</src>; <src>Float</src> for <src>Float</src> and
00067 //      <src>Complex</src>
00068 // <dt> <src>ConjugateType</src>
00069 // <dd> The corresponding complex type for a real type, and real type
00070 //      for a complex type. It is the type of the result if a Fourier
00071 //      Transform was to be done.
00072 // <dt> <src>PrecisionType</src>
00073 // <dd> The Type of the next higher numerical precision. I.e. <src>Double</src>
00074 //      or <src>DComplex</src>
00075 // </dl>
00076 // 
00077 // And the following characteristics:
00078 // <dl> 
00079 // <dt> <src>epsilon</src>
00080 // <dd> A Double containing the smallest value such that 1+epsilon is different
00081 //      from 1.
00082 // <dt> <src>minimum</src>
00083 // <dd> A Double containing the smallest positive representable number,
00084 //      excluding denormalised numbers.
00085 // <dt> <src>maximum</src>
00086 // <dd> A Double containing the largest representable number.
00087 // <dt> <src>size()</src>
00088 // <dd> The number of numeric values in the templated entity. It will be
00089 //      2 for complex numbers; 1 for real numbers.
00090 // <dt> <src>setImag(T &other, const BaseType &val)</src>
00091 // <dd> Set an imaginary part (for complex numbers) or a NOP (for reals).
00092 // <dt> <src>getValue(T &other, const uInt n)</src>
00093 // <dd> Get the <src>n%size()-th</src> value in the argument.
00094 //      For complex numbers the sequence is real, imaginary part.
00095 // <dt> <src>setValue(T &other, const BaseType &val, const uInt n)</src>
00096 // <dd> Set the <src>n%size()-th</src> value in the argument.
00097 //      For complex numbers the sequence is real, imaginary part.
00098 // </dl>
00099 //
00100 // For complex numbers these values are applicable to the real or imaginary
00101 // components separately.
00102 // 
00103 // The use of this class is best illustrated in a number of examples.
00104 //
00105 // A default template declaration is required by the C++ standard.
00106 // It should never be used, except through the specialisations.
00107 // The default types for ConjugateType and PrecisionType are deliberatly set to
00108 // a non-numeric type to further discourage the use of the non-specialized
00109 // class defined below. It also helps when using this class with the Sun native
00110 // compiler.
00111 // <note role=warning> The specialized instantiations seem to have a name with
00112 // an appended code. This is only for cxx2html reasons. The name is in all
00113 // cases <src>NumericTraits</src>
00114 // </note>
00115 //
00116 // This class is implemented as a number of specialisations for the
00117 // following data types.
00118 // <ul> 
00119 // <li> Float
00120 // <li> Double
00121 // <li> Complex
00122 // <li> DComplex
00123 // </ul>
00124 // This class should not be used with other template types and does nothing
00125 // except return its template type if it is used. ie. <br>
00126 // <src>NumericTraits<ArbitraryType>::ConjugateType</src> returns 
00127 //   <src>Char</src> and <br>
00128 // <src>NumericTraits<ArbitraryType>::PrecisionType</src> returns 
00129 //   <src>Char</src><br>
00130 // <src>NumericTraits<ArbitraryType>::epsilon</src> is undefined<br>
00131 // <src>NumericTraits<ArbitraryType>::minimum</src> is undefined<br>
00132 // <src>NumericTraits<ArbitraryType>::maximum</src> is undefined
00133 // </synopsis>
00134 //
00135 // <example>
00136 // <h4>Example 1:</h4>
00137 // Suppose you are writing a templated class that needs to do Fourier
00138 // Transforms. The FFTServer class can do FFT's of Float or Double data
00139 // types, but you need to doubly template it on the conjugate data type. To
00140 // avoid having the conjugate data type appear as a template in the class
00141 // you are writing you can use the ConjugateType typedef.
00142 // <srcblock> 
00143 // template<class T> class myClass {
00144 // private:
00145 // FFTServer<T, NumericTraits<T>::ConjugateType> server;
00146 // }
00147 // </srcblock>
00148 // The ConjugateType transforms
00149 // <ul>
00150 // <li> Float -> Complex
00151 // <li> Double -> DComplex
00152 // <li> Complex -> Float
00153 // <li> DComplex -> Double
00154 // </ul>
00155 //
00156 // <h4>Example 2:</h4>
00157 // Suppose you have a templated numerical integrator class. Because the
00158 // individual samples can be negative it is possible to add two numbers
00159 // of nearly equal magnitude but opposite sign and lose precision
00160 // considerably. One way to combat this is to make the accumulator variable
00161 // the next higher precision numerical type. The PrecisionType typedef
00162 // defines what type this is
00163 // <srcblock> 
00164 // template<class T> class Integrator {
00165 // private:
00166 // NumericTraits<T>::PrecisionType accumulator;
00167 // }
00168 // </srcblock>
00169 // The PrecisionType transforms
00170 // <ul>
00171 // <li> Float -> Double
00172 // <li> Double -> Double
00173 // <li> Complex -> DComplex
00174 // <li> DComplex -> DComplex
00175 // </ul>
00176 
00177 // <h4>Example 3:</h4>
00178 // Suppose you have a templated class that needs to use the <src>allNear</src>
00179 // functions from
00180 // <linkto group="ArrayMath.h#Array mathematical operations">ArrayMath</linkto>
00181 // to determine if a templated Array is near
00182 // one. The tolerance argument to the allNear function will depend on the
00183 // template type and this is not known until the template is instantiated. The
00184 // epsilon trait can be used to supply this value.
00185 
00186 // <srcblock> 
00187 // template<class T> void myClass<T>::myFunction(Array<T> & aArray) {
00188 //   if (allNear(aArray, T(1), NumericTraits<T>::epsilon))
00189 //     return;
00190 // // Do something
00191 // }
00192 // </srcblock>
00193 
00194 // <dl>
00195 // <dt><src>NumericTraits<T>::epsilon</src> 
00196 // <dd> is FLT_EPSILON for Float and Complex types and DBL_EPSILON for Double
00197 // and DComplex data types.
00198 // <dt><src>NumericTraits<T>::minimum</src>
00199 // <dd>is FLT_MIN for Float and complex Types and DBL_MIN for Double and
00200 // DComplex data types.
00201 // <dt><src>NumericTraits<T>::maximum</src>
00202 // <dd>is FLT_MAX for Float and complex Types and DBL_MAX for Double and
00203 // DComplex data types.
00204 // </dl>
00205 // See the <linkto class=Dummy_Constants_class">C class/namespace</linkto>
00206 // for the values of these variables.
00207 // </example>
00208 //
00209 // <motivation>
00210 // This is a nice way to make the Convolver class singly templated (as it
00211 // should be), even though the FFTServer it contains is doubly templated. 
00212 // </motivation>
00213 //
00214 // <thrown>
00215 // <li> This class does not throw any exceptions
00216 // </thrown>
00217 //
00218 // <todo asof="2002/06/25">
00219 // <li> Nothing (I hope!)
00220 // </todo>
00221 //
00222 
00223 template <class T> class NumericTraits {
00224 public:
00225   // Template argument
00226   typedef T    value_type;
00227   // Numeric type
00228   typedef Char BaseType;
00229   // Conjugate (<src>real<->complex</src>) type
00230   typedef Char ConjugateType; 
00231   // Higher precision type (<src>Float->Double</src>)
00232   typedef Char PrecisionType;      
00233   // Relevant minimum and maximum numbers
00234   // <group>
00235   static const Double & epsilon;
00236   static const Double & minimum;
00237   static const Double & maximum;
00238   // </group>
00239   // Number of relevant numeric values
00240   static uInt  size() { return 0; }
00241   // Set the imaginary part of a complex value only (a NOP for reals)
00242   static void setImag(T &, const BaseType &) {;}
00243   // Get the <src>n%size()-th</src> numeric value
00244   static BaseType getValue(const T &, const uInt) { return 0; }
00245   // Set the <src>n%size()-th</src> numeric value
00246   static void setValue(T &, const BaseType &, const uInt) {;}
00247 };
00248 
00249 #if defined NumericTraits_F
00250 #undef NumericTraits_F
00251 #endif
00252 #define NumericTraits_F NumericTraits
00253 
00254 // <summary>NumericTraits specialization for Float</summary>
00255 
00256 template <> class NumericTraits_F<Float> {
00257 public:
00258   // Template argument
00259   typedef Float    value_type;
00260   // Numeric type
00261   typedef Float    BaseType;
00262   // Conjugate (<src>real<->complex</src>) type
00263   typedef Complex  ConjugateType; 
00264   // Higher precision type (<src>Float->Double</src>)
00265   typedef Double   PrecisionType;      
00266   // Relevant minimum and maximum numbers
00267   // <group>
00268   static const Double & epsilon;
00269   static const Double & minimum;
00270   static const Double & maximum;
00271   // </group>
00272   // Number of relevant numeric values
00273   static uInt  size() { return 1; }
00274   // Set the imaginary part of a complex value only (a NOP for reals)
00275   static void setImag(value_type &, const BaseType &) {;}
00276   // Get the <src>n%size()-th</src> numeric value
00277   static BaseType getValue(const value_type &other, const uInt) {
00278     return other; }
00279   // Set the <src>n%size()-th</src> numeric value
00280   static void setValue(value_type &other, const BaseType &val, const uInt) {
00281     other = val; }
00282 };
00283 
00284 #undef NumericTraits_F
00285 
00286 #if defined NumericTraits_D
00287 #undef NumericTraits_D
00288 #endif
00289 #define NumericTraits_D NumericTraits
00290 
00291 // <summary>NumericTraits specialization for Double</summary>
00292 
00293 template <> class NumericTraits_D<Double> {
00294 public:
00295   // Template argument
00296   typedef Double    value_type;
00297   // Numeric type
00298   typedef Double    BaseType;
00299   // Conjugate (<src>real<->complex</src>) type
00300   typedef DComplex  ConjugateType; 
00301   // Higher precision type (<src>Float->Double</src>)
00302   typedef Double    PrecisionType;      
00303   // Relevant minimum and maximum numbers
00304   // <group>
00305   static const Double & epsilon;
00306   static const Double & minimum;
00307   static const Double & maximum;
00308   // </group>
00309   // Number of relevant numeric values
00310   static uInt  size() { return 1; }
00311   // Set the imaginary part of a complex value only (a NOP for reals)
00312   static void setImag(value_type &, const BaseType &) {;}
00313   // Get the <src>n%size()-th</src> numeric value
00314   static BaseType getValue(const value_type &other, const uInt) {
00315     return other; }
00316   // Set the <src>n%size()-th</src> numeric value
00317   static void setValue(value_type &other, const BaseType &val, const uInt) {
00318     other = val; }
00319 };
00320 
00321 #undef NumericTraits_D
00322 
00323 #if defined NumericTraits_C
00324 #undef NumericTraits_C
00325 #endif
00326 #define NumericTraits_C NumericTraits
00327 
00328 // <summary>NumericTraits specialization for Complex</summary>
00329 
00330 template <> class NumericTraits_C<Complex> {
00331 public:
00332   // Template argument
00333   typedef Complex    value_type;
00334   // Numeric type
00335   typedef Float      BaseType;
00336   // Conjugate (<src>real<->complex</src>) type
00337   typedef Float      ConjugateType; 
00338   // Higher precision type (<src>Float->Double</src>)
00339   typedef DComplex   PrecisionType;      
00340   // Relevant minimum and maximum numbers
00341   // <group>
00342   static const Double & epsilon;
00343   static const Double & minimum;
00344   static const Double & maximum;
00345   // </group>
00346   // Number of relevant numeric values
00347   static uInt  size() { return 2; }
00348   // Set the imaginary part of a complex value only (a NOP for reals)
00349   static void setImag(value_type &other, const BaseType &val) {
00350     other = value_type(other.real(), val); }
00351   // Get the <src>n%size()-th</src> numeric value
00352   static BaseType getValue(const value_type &other, const uInt n) {
00353     return ((n%2 == 0) ? other.real() : other.imag()); }
00354   // Set the <src>n%size()-th</src> numeric value
00355   static void setValue(value_type &other, const BaseType &val, const uInt n) {
00356     other = (n%2 == 0) ? value_type(val, other.imag()) :
00357       value_type(other.real(), val); }
00358 };
00359 
00360 #undef NumericTraits_C
00361 
00362 #if defined NumericTraits_DC
00363 #undef NumericTraits_DC
00364 #endif
00365 #define NumericTraits_DC NumericTraits
00366 
00367 // <summary>NumericTraits specialization for DComplex</summary>
00368 
00369 template <> class NumericTraits_DC<DComplex> {
00370 public:
00371   // Template argument
00372   typedef DComplex    value_type;
00373   // Numeric type
00374   typedef Double      BaseType;
00375   // Conjugate (<src>real<->complex</src>) type
00376   typedef Double      ConjugateType; 
00377   // Higher precision type (<src>Float->Double</src>)
00378   typedef DComplex   PrecisionType;      
00379   // Relevant minimum and maximum numbers
00380   // <group>
00381   static const Double & epsilon;
00382   static const Double & minimum;
00383   static const Double & maximum;
00384   // </group>
00385   // Number of relevant numeric values
00386   static uInt  size() { return 2; }
00387   // Set the imaginary part of a complex value only (a NOP for reals)
00388   static void setImag(value_type &other, const BaseType &val) {
00389     other = value_type(other.real(), val); }
00390   // Get the <src>n%size()-th</src> numeric value
00391   static BaseType getValue(const value_type &other, const uInt n) {
00392     return ((n%2 == 0) ? other.real() : other.imag()); }
00393   // Set the <src>n%size()-th</src> numeric value
00394   static void setValue(value_type &other, const BaseType &val, const uInt n) {
00395     other = (n%2 == 0) ? value_type(val, other.imag()) :
00396       value_type(other.real(), val); }
00397 };
00398 
00399 #undef NumericTraits_DC
00400 
00401 
00402 } //# NAMESPACE CASA - END
00403 
00404 #endif