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