| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

In This Package:

Lomont.cpp

Go to the documentation of this file.
00001 // $Id: Lomont.cpp,v 1.1 2008/11/08 15:03:39 ibelyaev Exp $
00002 // ============================================================================
00003 // CVS Tag %Name:%, version $Revision: 1.1 $
00004 // ============================================================================
00005 // include files
00006 // ============================================================================
00007 // STD & STL 
00008 // ============================================================================
00009 #include <iostream>
00010 #include <limits>
00011 #include <cassert>
00012 #include <cmath>
00013 #include <vector>
00014 // ============================================================================
00015 // LHCbMath
00016 // ============================================================================
00017 #include "LHCbMath/Lomont.h"
00018 // ============================================================================
00019 // Boost 
00020 // ============================================================================
00021 #include "boost/static_assert.hpp"
00022 #include "boost/integer_traits.hpp"
00023 // ============================================================================
00024 /*  equality comparion of float numbers using as the metric the maximal 
00025  *  number of Units in the Last Place (ULP).
00026  *  It is a slightly modified version of very efficient implementation 
00027  *  of the initial Bruce Dawson's algorithm by Chris Lomont.
00028  *
00029  *  @see www.lomont.org 
00030  *  @see http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
00031  *
00032  *  Lomont claims the algorithm is factor 2-10 more efficient 
00033  *  with respect to  Knuth's algorithm fomr comparions of floating number 
00034  *  using the relative precision.
00035  *
00036  *  The effective relative difference depends on the choice of 
00037  *   <c>maxULPS</c>:
00038  *  - For the case of maxULPs=1, (of cource it is totally unphysical case!!!)
00039  *  the effective relative precision r = |a-b|/(|a|+|b|)is 
00040  *  between 3.5e-8 and 5.5e-8 for |a|,|b|>1.e-37, and 
00041  *  then it quickly goes to ~1 
00042  *  - For the case of maxULPS=10 
00043  *  the effective relative precision is 
00044  *  between 3e-8 and 6e-7 for |a|,|b|>1.e-37, and 
00045  *  then it quickly goes to ~1 
00046  *  - For the case of maxULPS=100 
00047  *  the effective relative precision is 
00048  *  around ~6e-6 for |a|,|b|>1.e-37, and 
00049  *  then it quickly goes to ~1 
00050  *  - For the case of maxULPS=1000 
00051  *  the effective relative precision is 
00052  *  around ~6e-5 for |a|,|b|>1.e-37, and 
00053  *  then it quickly goes to ~1 
00054  *  
00055  *  @param  af the first number 
00056  *  @param  bf the second number 
00057  *  @param  maxULPS the maximal metric deciation in the terms of 
00058  *                 maximal number of units in the last place
00059  *  @author Vanya BELYAEV  Ivan.Belyaev@nikhef.nl
00060  */
00061 // ============================================================================
00062 bool LHCb::Math::lomont_compare_float 
00063 ( const float          af      , 
00064   const float          bf      , 
00065   const unsigned short maxULPs ) 
00066 {
00067   // ==========================================================================
00068   // prerequisites:
00069   BOOST_STATIC_ASSERT( std::numeric_limits<float>          ::is_specialized &&
00070                        boost::integer_traits<int>          ::is_specialized && 
00071                        boost::integer_traits<unsigned int> ::is_specialized &&
00072                        sizeof(float)==sizeof(int)                           && 
00073                        sizeof(float)==sizeof(unsigned int)                  &&
00074                        32 == boost::integer_traits<unsigned int>::digits    ) ;
00075   // ==========================================================================
00076   
00077   int ai = *reinterpret_cast<const int*>( &af ) ;
00078   int bi = *reinterpret_cast<const int*>( &bf ) ;
00079   
00080   int test = (((unsigned int)(ai^bi))>>31)-1;
00081   
00082   // assert ( (0==test) || ( boost::integer_traits<unsigned int>::const_max == test ) ) ;
00083   
00084   int diff = ((( boost::integer_traits<int>::const_min - ai ) & (~test)) | ( ai& test )) - bi ;
00085   
00086   int maxDiff_ = maxULPs ;
00087   
00088   int v1 = maxDiff_ + diff ;
00089   int v2 = maxDiff_ - diff ;
00090   
00091   return 0<=(v1|v2) ;
00092 }
00093 // ============================================================================
00094 /*  get the floating number that representation 
00095  *  is different with respect  to the argument for 
00096  *  the certain number of "Units in the Last Position".
00097  *  For ulps=1, it is just next float number, for ulps=-1 is is the 
00098  *  previous one.
00099  *
00100  *  This routine is very convinient to test the parameter maxULPS for
00101  *  the routine LHCb::Math::lomont_compare 
00102  *
00103  *  @see LHCb:Math::lomont_compare
00104  *  @param af the reference number 
00105  *  @param ulps the bias 
00106  *  @return the biased float number (on distance "ulps")
00107  *  @author Vanya BELYAEV  Ivan.Belyaev@nikhef.nl
00108  *  @date 2008-11-08
00109  */  
00110 // ============================================================================
00111 float LHCb::Math::next_float ( const float af , const short ulps ) 
00112 {
00114   BOOST_STATIC_ASSERT( std::numeric_limits<float> ::is_specialized &&
00115                        std::numeric_limits<int>   ::is_specialized && 
00116                        sizeof(float)==sizeof(int) ) ;
00117   
00118   int ai = *reinterpret_cast<const int*>( &af ) ;
00119   ai += ulps ;
00120   return *reinterpret_cast<float*>(&ai) ;
00121 }
00122 // ============================================================================
00123 namespace 
00124 {
00125   // ========================================================================
00126 #ifdef _WIN32
00127   struct _Longs 
00128   {
00129     typedef __int64            Long   ;
00130     typedef unsigned __int64   ULong  ;
00131   } ;  
00132 #else
00133   template <bool I> 
00134   struct __Longs ;
00135   template <>
00136   struct __Longs<true>
00137   {
00138     typedef long               Long   ;
00139     typedef unsigned long      ULong  ;
00140   } ;
00141   template <>
00142   struct __Longs<false>
00143   {
00144     typedef long long               Long   ;
00145     typedef unsigned long long      ULong  ;
00146   } ;
00147   struct _Longs : public __Longs<sizeof(double)==sizeof(long)>{};
00148 #endif 
00149   
00151   typedef _Longs::Long  Long  ;
00152   typedef _Longs::ULong ULong ;
00153   
00155   BOOST_STATIC_ASSERT( std::numeric_limits<double>        ::is_specialized &&
00156                        std::numeric_limits<Long>          ::is_specialized && 
00157                        std::numeric_limits<ULong> ::is_specialized &&
00158                        boost::integer_traits<ULong> ::is_specialized &&
00159                        boost::integer_traits<Long> ::is_specialized &&
00160                        sizeof(double)==sizeof(Long)          && 
00161                        sizeof(double)==sizeof(ULong)  &&
00162                        64 == std::numeric_limits<ULong>::digits ) ;
00163 }
00164 // ============================================================================
00165 /*  equality comparison of float numbers using as the metric the maximal 
00166  *  number of Units in the Last Place (ULP).
00167  *  It is a slightly modified version of very efficient implementation 
00168  *  of the initial Bruce Dawson's algorithm by Chris Lomont.
00169  *
00170  *  @see www.lomont.org 
00171  *  @see http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
00172  *
00173  *  C.Lomont claims the algorithm is factor 2-10 more efficient 
00174  *  with respect to  Knuth's algorithm fomr comparions of floating number 
00175  *  using the relative precision.
00176  *
00177  *  The effective relative difference depends on the choice of 
00178  *   <c>maxULPS</c>:
00179  *  - For the case of maxULPs=1, (of cource it is totally unphysical case!!!)
00180  *  the effective relative precision r = |a-b|/(|a|+|b|)is 
00181  *  ~6e-16 for |a|,|b|>1.e-304, and 
00182  *  then it quickly goes to ~1 
00183  *  
00184  *  @param  af the first number 
00185  *  @param  bf the second number 
00186  *  @param  maxULPS the maximal metric deciation in the terms of 
00187  *                 maximal number of units in the last place
00188  *  @author Vanya BELYAEV  Ivan.Belyaev@nikhef.nl
00189  *  @date 2008-11-08
00190  */
00191 // ============================================================================
00192 bool LHCb::Math::lomont_compare_double 
00193 ( const double       af      , 
00194   const double       bf      , 
00195   const unsigned int maxULPs ) 
00196 {
00198   BOOST_STATIC_ASSERT( std::numeric_limits<double>        ::is_specialized &&
00199                        std::numeric_limits<Long>          ::is_specialized && 
00200                        std::numeric_limits<ULong> ::is_specialized &&
00201                        boost::integer_traits<ULong> ::is_specialized &&
00202                        boost::integer_traits<Long> ::is_specialized &&
00203                        sizeof(double)==sizeof(Long)          && 
00204                        sizeof(double)==sizeof(ULong)  &&
00205                        64 == std::numeric_limits<ULong>::digits ) ;
00206   
00207   Long ai = *reinterpret_cast<const Long*>( &af ) ;
00208   Long bi = *reinterpret_cast<const Long*>( &bf ) ;
00209   
00210   Long test = (((ULong)(ai^bi))>>63)-1;
00211   
00212   // assert ( (0==test) || ( boost::integer_traits<ULong>::const_max == test ) ) ;
00213   
00214   Long diff = ((( boost::integer_traits<Long>::const_min - ai ) & (~test)) | ( ai& test )) - bi ;
00215   
00216   Long maxDiff_ = maxULPs ;
00217   
00218   Long v1 = maxDiff_ + diff ;
00219   Long v2 = maxDiff_ - diff ;
00220   
00221   return 0<=(v1|v2) ;
00222 }
00223 // ============================================================================
00224 /*  Get the floating number that representation 
00225  *  is different with respect  to the argument for 
00226  *  the certain number of "Units in the Last Position".
00227  *  For ulps=1, it is just next float number, for ulps=-1 is is the 
00228  *  previous one.
00229  *
00230  *  This routine is very convinient to test the parameter maxULPS for
00231  *  the routine LHCb::Math::lomont_compare_float 
00232  *
00233  *  @see LHCb:Math::lomont_compare
00234  *  @param af the reference number 
00235  *  @param ulps the bias 
00236  *  @return the biased float number (on distance "ulps")
00237  *  @author Vanya BELYAEV  Ivan.Belyaev@nikhef.nl
00238  *  @date 2008-11-08
00239  */  
00240 // ============================================================================
00241 double LHCb::Math::next_double ( const double ad , const short ulps ) 
00242 {
00244   BOOST_STATIC_ASSERT( std::numeric_limits<double> ::is_specialized &&
00245                        std::numeric_limits<Long>   ::is_specialized && 
00246                        sizeof(double)==sizeof(Long) ) ;
00247   
00248   Long al = *reinterpret_cast<const Long*>( &ad ) ;
00249   al += ulps ;
00250   return *reinterpret_cast<double*>(&al) ;
00251 }
00252 // ============================================================================
00253   
00254 
00255 // ============================================================================
00256 // The END 
00257 // ============================================================================
00258   
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

Generated on Mon Apr 11 20:02:57 2011 for LHCbMath by doxygen 1.4.7