core/vnl/vnl_math.cxx
Go to the documentation of this file.
00001 // This is core/vnl/vnl_math.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 
00008 #include "vnl_math.h"
00009 #include <vxl_config.h>
00010 
00011 #if defined(VCL_VC) || defined(__MINGW32__)
00012 // I don't think we need this, because <ieeefp.h> is available -- fsm
00013 # include <float.h> // for 'isnan' and 'finite'
00014 // # define isnan _isnan
00015 # define finite _finite
00016 # define finitef _finite
00017 #ifndef finitel
00018 # define finitel _finite
00019 #endif
00020 # define isnan _isnan
00021 #elif VXL_IEEEFP_HAS_FINITE
00022 # include <ieeefp.h>
00023 # ifndef finitef
00024 #  define finitef finite
00025 # endif
00026 # ifndef finitel
00027 #  define finitel finite
00028 # endif
00029 
00030 #elif VXL_C_MATH_HAS_FINITE
00031 # include <math.h> // dont_vxl_filter: this is *not* supposed to be <cmath>
00032 # if !VXL_C_MATH_HAS_FINITEF
00033 #  define finitef finite
00034 # endif
00035 # if !VXL_C_MATH_HAS_FINITEL
00036 #  define finitel finite
00037 # endif
00038 
00039 #elif defined(__hpux)
00040 # include <math.h> // dont_vxl_filter: this is *not* supposed to be <cmath>
00041 # define finite _Isfinite
00042 # define finitef _Isfinitef
00043 # define finitel _Isfinite
00044 
00045 #elif defined(SYSV)
00046 // needed on platforms with finite() declared in strange places
00047 extern "C" int finite(double);
00048 # define finitef finite
00049 # define finitel finite
00050 
00051 #elif defined(VCL_BORLAND)
00052 # include <math.h> // dont_vxl_filter: this is *not* supposed to be <cmath>
00053 # include <float.h>
00054 
00055 #else
00056 # warning finite() is not declared on this platform
00057 # define VNL_HAS_NO_FINITE
00058 #endif
00059 
00060 #ifdef VCL_SUNPRO_CC_5
00061 # include <math.h> // dont_vxl_filter: no HUGE_VAL or isnan() in <cmath>
00062 #endif
00063 
00064 // On Mac OS X Tiger in C++ the math.h header defines an inline __isnan
00065 // that gets compiled here into an internal-linkage symbol.  Then at
00066 // link time the relocation entry from libm.dylib confuses the linker
00067 // because it thinks the entry applies to the static version of the
00068 // symbol.  We need to avoid use of the inline version by never
00069 // calling __isnan in C++ code.
00070 #if defined(__APPLE__)
00071 # include <Availability.h>
00072 # if MAC_OS_X_VERSION_MAX_ALLOWED == 1040
00073 #  include <math.h> // dont_vxl_filter: this is *not* supposed to be <cmath>
00074 #  if VXL_APPLE_HAS_ISNAND
00075 #   define isnan(x) __isnand((double)x)
00076 #  else
00077 #   define isnan(x) __inline_isnand((double)x)
00078 #  endif
00079 # endif
00080 #endif
00081 
00082 //--------------------------------------------------------------------------------
00083 
00084 #if !VCL_STATIC_CONST_INIT_FLOAT_NO_DEFN
00085 
00086 //: constants
00087 const double vnl_math::e                VCL_STATIC_CONST_INIT_FLOAT_DEFN( 2.71828182845904523540 );
00088 const double vnl_math::log2e            VCL_STATIC_CONST_INIT_FLOAT_DEFN( 1.44269504088896340740 );
00089 const double vnl_math::log10e           VCL_STATIC_CONST_INIT_FLOAT_DEFN( 0.43429448190325182765 );
00090 const double vnl_math::ln2              VCL_STATIC_CONST_INIT_FLOAT_DEFN( 0.69314718055994530942 );
00091 const double vnl_math::ln10             VCL_STATIC_CONST_INIT_FLOAT_DEFN( 2.30258509299404568402 );
00092 const double vnl_math::pi               VCL_STATIC_CONST_INIT_FLOAT_DEFN( 3.14159265358979323846 );
00093 const double vnl_math::pi_over_2        VCL_STATIC_CONST_INIT_FLOAT_DEFN( 1.57079632679489661923 );
00094 const double vnl_math::pi_over_4        VCL_STATIC_CONST_INIT_FLOAT_DEFN( 0.78539816339744830962 );
00095 const double vnl_math::pi_over_180      VCL_STATIC_CONST_INIT_FLOAT_DEFN( 0.01745329251994329577 );
00096 const double vnl_math::one_over_pi      VCL_STATIC_CONST_INIT_FLOAT_DEFN( 0.31830988618379067154 );
00097 const double vnl_math::two_over_pi      VCL_STATIC_CONST_INIT_FLOAT_DEFN( 0.63661977236758134308 );
00098 const double vnl_math::deg_per_rad      VCL_STATIC_CONST_INIT_FLOAT_DEFN( 57.2957795130823208772 );
00099 const double vnl_math::two_over_sqrtpi  VCL_STATIC_CONST_INIT_FLOAT_DEFN( 1.12837916709551257390 );
00100 const double vnl_math::one_over_sqrt2pi VCL_STATIC_CONST_INIT_FLOAT_DEFN( 0.39894228040143267794 );
00101 const double vnl_math::sqrt2            VCL_STATIC_CONST_INIT_FLOAT_DEFN( 1.41421356237309504880 );
00102 const double vnl_math::sqrt1_2          VCL_STATIC_CONST_INIT_FLOAT_DEFN( 0.70710678118654752440 );
00103 const double vnl_math::sqrt1_3          VCL_STATIC_CONST_INIT_FLOAT_DEFN( 0.57735026918962573106 );
00104 const double vnl_math::euler            VCL_STATIC_CONST_INIT_FLOAT_DEFN( 0.57721566490153286061 );
00105 
00106 //: IEEE double machine precision
00107 const double vnl_math::eps              VCL_STATIC_CONST_INIT_FLOAT_DEFN( 2.2204460492503131e-16 );
00108 const double vnl_math::sqrteps          VCL_STATIC_CONST_INIT_FLOAT_DEFN( 1.4901161193847660e-08 );
00109 
00110 //: IEEE single machine precision
00111 const float vnl_math::float_eps         VCL_STATIC_CONST_INIT_FLOAT_DEFN( 1.1920928960e-7f );
00112 const float vnl_math::float_sqrteps     VCL_STATIC_CONST_INIT_FLOAT_DEFN( 3.4526698307e-4f );
00113 
00114 #endif
00115 
00116 //--------------------------------------------------------------------------------
00117 //: Return true iff x is "Not a Number"
00118 #if VXL_CXX11
00119 //: Return true iff x is "Not a Number"
00120 bool vnl_math_isnan(float x) { return std::isnan(x); }
00121 //: Return true iff x is "Not a Number"
00122 bool vnl_math_isnan(double x) { return std::isnan(x); }
00123 //: Return true iff x is "Not a Number"
00124 bool vnl_math_isnan(long double x) { return std::isnan(x); }
00125 #elif defined(VCL_ICC)
00126 #include <mathimf.h> // defines isnanf, isnan, and isnanl
00127 //: Return true iff x is "Not a Number"
00128 bool vnl_math_isnan(float x) { return isnanf(x); }
00129 //: Return true iff x is "Not a Number"
00130 bool vnl_math_isnan(double x) { return isnan(x); }
00131 //: Return true iff x is "Not a Number"
00132 bool vnl_math_isnan(long double x) { return isnanl(x); }
00133 #elif defined(VCL_BORLAND)
00134 //: Return true iff x is "Not a Number"
00135 bool vnl_math_isnan(float x) { return _isnan(x); }
00136 //: Return true iff x is "Not a Number"
00137 bool vnl_math_isnan(double x) { return _isnan(x); }
00138 //: Return true iff x is "Not a Number"
00139 bool vnl_math_isnan(long double x) { return _isnanl(x); }
00140 #elif !defined(VNL_HAS_NO_FINITE) && !defined(VCL_SGI_CC_7) && !defined(__alpha__) && !defined(VCL_WIN32)
00141 //: Return true iff x is "Not a Number"
00142 bool vnl_math_isnan(float x) { return x != x; } // causes "floating exception" on alpha & sgi
00143 //: Return true iff x is "Not a Number"
00144 bool vnl_math_isnan(double x) { return x != x; }
00145 //: Return true iff x is "Not a Number"
00146 bool vnl_math_isnan(long double x) { return x != x; }
00147 #else
00148 // Auxiliary function to simplify notation
00149 # ifndef DEBUG
00150 static inline unsigned int bMp(void*x,unsigned int y,int p=0){return ((((unsigned int*)x)[p])&y);}
00151 static inline bool bMe(void*x,unsigned int y,int p=0){return ((((unsigned int*)x)[p])&y)==y;}
00152 # else
00153 # include <vcl_iostream.h>
00154 static inline unsigned int bMp(void* x, unsigned int y, int p=0)
00155 {
00156   unsigned char* v=(unsigned char*)x;
00157   vcl_cout<<int(v[4*p])<<' '<<int(v[4*p+1])<<' '<<int(v[4*p+2])<<' '<<int(v[4*p+3])<<" & ";
00158   v=(unsigned char*)(&y);
00159   vcl_cout<<int(v[0])<<' '<<int(v[1])<<' '<<int(v[2])<<' '<<int(v[3])<<" = ";
00160   unsigned int z = ((((unsigned int*)x)[p]) & y);
00161   v=(unsigned char*)(&z);
00162   vcl_cout<<int(v[0])<<' '<<int(v[1])<<' '<<int(v[2])<<' '<<int(v[3]);
00163   if (z == y) vcl_cout<<" ==";
00164   vcl_cout << '\n';
00165   return z;
00166 }
00167 
00168 static inline bool bMe(void* x, unsigned int y, int p=0) { return bMp(x,y,p) == y; }
00169 # endif
00170 # if VXL_BIG_ENDIAN
00171 static const int sz_f = 0;
00172 static const int sz_d = 0;
00173 static const int sz_l = 0;
00174 # else
00175 static const int sz_f = sizeof(float)/sizeof(int) -1;
00176 static const int sz_d = sizeof(double)/sizeof(int) -1;
00177 static const int sz_l = sizeof(long double)/sizeof(int) -1;
00178 # endif
00179 // Assume IEEE floating point number representation
00180 bool vnl_math_isnan( float x){return bMe(&x,0x7f800000L,sz_f)&&bMp(&x,0x007fffffL,sz_f);}
00181 bool vnl_math_isnan(double x){return bMe(&x,0x7ff00000L,sz_d)&&(bMp(&x,0x000fffffL,sz_d)||bMp(&x,0xffffffffL,1-sz_d));}
00182 bool vnl_math_isnan(long double x)
00183 {
00184   if (sizeof(long double) == 8) return bMe(&x,0x7ff00000L,sz_l) && (bMp(&x,0x000fffffL,sz_l)||bMp(&x,0xffffffffL,1-sz_d));
00185   else if (sizeof(long double) <= 12) // This code doesn't properly check the less significant
00186                                       // bytes for non-zero-ness to distinguish inf from nan
00187                                       // see http://babbage.cs.qc.cuny.edu/IEEE-754/References.xhtml#tables
00188 # if defined LDBL_MANT_DIG && LDBL_MANT_DIG<=53
00189     return bMe(&x,0x4001ffffL,sz_l) && bMp(&x,0x40000000,sz_l-4);
00190 # else
00191     return bMe(&x,0x7ff00000L,sz_l) && bMp(&x,0x000fffffL,sz_l-4);
00192 # endif
00193   else
00194     return bMe(&x,0x7ff00000L,sz_l) && bMp(&x,0x0000ffffL,sz_l);
00195 }
00196 #endif
00197 
00198 // fsm
00199 // On linux noshared builds, with optimisation on, calling 'finite' within the
00200 // scope of vnl_math causes vnl_math_isinf to be called. This blows the stack.
00201 // Plausible theory : 'finite' is a preprocessor macro, defined in terms of a
00202 // macro called 'isinf'.
00203 // Doesn't seem to be an issue with ICC 8
00204 #if defined(isinf) && !defined(VCL_ICC_8)
00205 # if defined(__GNUC__) || defined(VCL_METRO_WERKS) || defined(__INTEL_COMPILER)
00206 // I do not know if MW accepts #warning. Comment out the #undef if not.
00207 #  warning macro isinf is defined
00208 #  undef isinf
00209 # else
00210 // do not fail silently
00211 #  error macro isinf is defined
00212 # endif
00213 #endif
00214 
00215 #if VXL_CXX11
00216 //: Return true if x is neither NaN nor Inf.
00217 bool vnl_math_isfinite(float x) { return std::isfinite(x) != 0; }
00218 //: Return true if x is neither NaN nor Inf.
00219 bool vnl_math_isfinite(double x) { return std::isfinite(x) != 0; }
00220 //: Return true if x is neither NaN nor Inf.
00221 bool vnl_math_isfinite(long double x) { return std::isfinite(x) != 0; }
00222 #elif defined(VCL_BORLAND)
00223 //: Return true if x is neither NaN nor Inf.
00224 bool vnl_math_isfinite(float x) { return _finite(x) != 0; }
00225 //: Return true if x is neither NaN nor Inf.
00226 bool vnl_math_isfinite(double x) { return _finite(x) != 0; }
00227 //: Return true if x is neither NaN nor Inf.
00228 bool vnl_math_isfinite(long double x) { return _finitel(x) != 0 && !_isnanl(x); }
00229 #elif !defined(VNL_HAS_NO_FINITE)
00230 //: Return true if x is neither NaN nor Inf.
00231 bool vnl_math_isfinite(float x) { return finitef(x) != 0; }
00232 //: Return true if x is neither NaN nor Inf.
00233 bool vnl_math_isfinite(double x) { return finite(x) != 0; }
00234 //: Return true if x is neither NaN nor Inf.
00235 bool vnl_math_isfinite(long double x) { return finitel(x) != 0; }
00236 #else
00237 // Assume IEEE floating point number representation
00238 bool vnl_math_isfinite(float x) { return !bMe(&x,0x7f800000L,sz_f) && bMp(&x,0x7fffffffL,sz_f) != 0x7f7fffffL; }
00239 bool vnl_math_isfinite(double x) { return !bMe(&x,0x7ff00000L,sz_d); }
00240 bool vnl_math_isfinite(long double x)
00241 {
00242   if (sizeof(long double) == 8) return !bMe(&x,0x7ff00000L,sz_l);
00243   else if (sizeof(long double) <= 12) return !bMe(&x,0xbfff7fffL,sz_l) && !bMe(&x,0x4001ffffL,sz_l);
00244   else return !bMe(&x,0x7ff70000L,sz_l);
00245 }
00246 #endif
00247 
00248 
00249 #if VXL_CXX11
00250 //: Return true if x is inf
00251 bool vnl_math_isinf(float x) { return std::isinf(x) != 0; }
00252 //: Return true if x is inf
00253 bool vnl_math_isinf(double x) { return std::isinf(x) != 0; }
00254 //: Return true if x is inf
00255 bool vnl_math_isinf(long double x) { return std::isinf(x) != 0; }
00256 #elif defined(VCL_BORLAND)
00257 //: Return true if x is inf
00258 bool vnl_math_isinf(float x) { return !_finite(x) && !vnl_math_isnan(x); }
00259 //: Return true if x is inf
00260 bool vnl_math_isinf(double x) { return !_finite(x) && !vnl_math_isnan(x); }
00261 //: Return true if x is inf
00262 bool vnl_math_isinf(long double x) { return !_finitel(x) && !vnl_math_isnan(x); }
00263 #elif !defined(VNL_HAS_NO_FINITE)
00264 //: Return true if x is inf
00265 bool vnl_math_isinf(float x) { return !finitef(x) && !vnl_math_isnan(x); }
00266 //: Return true if x is inf
00267 bool vnl_math_isinf(double x) { return !finite(x) && !vnl_math_isnan(x); }
00268 //: Return true if x is inf
00269 bool vnl_math_isinf(long double x) { return !finitel(x) && !vnl_math_isnan(x); }
00270 #else
00271 // Assume IEEE floating point number representation
00272 bool vnl_math_isinf(float x) {return(bMe(&x,0x7f800000L,sz_f)&&!bMp(&x,0x007fffffL,sz_f))||bMp(&x,0x7fffffffL,sz_f)==0x7f7fffffL;}
00273 bool vnl_math_isinf(double x) { return bMe(&x,0x7ff00000L,sz_d) && !bMp(&x,0x000fffffL,sz_d); }
00274 bool vnl_math_isinf(long double x)
00275 {
00276   if (sizeof(long double) == 8) return bMe(&x,0x7ff00000L,sz_l) && !bMp(&x,0x000fffffL,sz_l);
00277   else if (sizeof(long double) <= 12) return (bMe(&x,0xbfff7fffL,sz_l)||bMe(&x,0x4001ffffL,sz_l))&&!bMp(&x,0x40000000,sz_l-4);
00278   else return bMe(&x,0x7ff70000L,sz_l) && !bMp(&x,0x0008ffffL,sz_l);
00279 }
00280 #endif
00281 
00282 //----------------------------------------------------------------------
00283 
00284 //: Type-accessible infinities for use in templates.
00285 template <class T> T vnl_huge_val(T);
00286 #ifndef VCL_ICC_81
00287 double vnl_huge_val(double) { return HUGE_VAL; }
00288 float  vnl_huge_val(float)  { return (float)HUGE_VAL; }
00289 #else
00290 // workaround ICC warning that 0x1.0p2047 cannot be represented exactly.
00291 double vnl_huge_val(double) { return // 2^2047
00292 16158503035655503650357438344334975980222051334857742016065172713762\
00293 32756943394544659860070576145673184435898046094900974705977957524546\
00294 05475440761932241415603154386836504980458750988751948260533980288191\
00295 92033784138396109321309878080919047169238085235290822926018152521443\
00296 78794577053290430377619956196519276095716669483417121034248739328228\
00297 47474280880176631610290389028296655130963542301570751292964320885583\
00298 62971801859230928678799175576150822952201848806616643615613562842355\
00299 41010486257855086346566173483927129032834896752299863417649931910776\
00300 25831947186677718010677166148023226592393024760740967779268055297981\
00301 15328.0; }
00302 float  vnl_huge_val(float)  { return // 2^255
00303 57896044618658097711785492504343953926634992332820282019728792003956\
00304 564819968.0f; }
00305 #endif
00306 #ifdef _INT_64BIT_
00307 long int vnl_huge_val(long int) { return 0x7fffffffffffffffL; }
00308 int    vnl_huge_val(int)    { return 0x7fffffffffffffffL; }
00309 #else
00310 int    vnl_huge_val(int)    { return 0x7fffffff; }
00311 #endif
00312 short  vnl_huge_val(short)  { return 0x7fff; }
00313 char   vnl_huge_val(char)   { return 0x7f; }
00314 
00315 
00316 //----------------------------------------------------------------------
00317 double vnl_math::angle_0_to_2pi(double angle)
00318 {
00319   double a;
00320   if (angle>=2*vnl_math::pi)
00321     a = vcl_fmod (angle,vnl_math::pi*2);
00322   else if (angle < 0)
00323     a = (2*vnl_math::pi+ vcl_fmod (angle,2*vnl_math::pi));
00324   else
00325     a= angle;
00326 
00327   // added by Nhon: these two lines of code is to fix the bug when
00328   // angle = -1.1721201390607859e-016
00329   // then after all the computation, we get
00330   // a = 6.2831853071795862 == 2*vnl_math::pi !!!!!!!
00331   // this situation can happen is when a is very close to zero.
00332 
00333   if (!(a>=0 && a<2*vnl_math::pi)) {
00334     a = 0;
00335   }
00336   return a;
00337 }