00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "high-precision-128.h"
00021 #include "ns3/test.h"
00022 #include <math.h>
00023 #include <iostream>
00024
00025 namespace ns3 {
00026
00027 #ifdef GATHER_STATISTICS
00028 int HighPrecision::m_nfastadds = 0;
00029 int HighPrecision::m_nfastsubs = 0;
00030 int HighPrecision::m_nfastmuls = 0;
00031 int HighPrecision::m_nfastcmps = 0;
00032 int HighPrecision::m_nfastgets = 0;
00033 int HighPrecision::m_nslowadds = 0;
00034 int HighPrecision::m_nslowsubs = 0;
00035 int HighPrecision::m_nslowmuls = 0;
00036 int HighPrecision::m_nslowcmps = 0;
00037 int HighPrecision::m_nslowgets = 0;
00038 int HighPrecision::m_ndivs = 0;
00039 int HighPrecision::m_nconversions = 0;
00040
00041 void
00042 HighPrecision::PrintStats (void)
00043 {
00044 double nadds = m_nfastadds + m_nslowadds;
00045 double nsubs = m_nfastsubs + m_nslowsubs;
00046 double ncmps = m_nfastcmps + m_nslowcmps;
00047 double nmuls = m_nfastmuls + m_nslowmuls;
00048 double ngets = m_nfastgets + m_nslowgets;
00049 double fast_add_ratio = m_nfastadds / nadds;
00050 double fast_sub_ratio = m_nfastsubs / nsubs;
00051 double fast_cmp_ratio = m_nfastcmps / ncmps;
00052 double fast_mul_ratio = m_nfastmuls / nmuls;
00053 double fast_get_ratio = m_nfastgets / ngets;
00054
00055 std::cout <<
00056 "add="<<fast_add_ratio<<std::endl<<
00057 "sub="<<fast_sub_ratio<<std::endl<<
00058 "cmp="<<fast_cmp_ratio<<std::endl<<
00059 "mul="<<fast_mul_ratio<<std::endl<<
00060 "get="<<fast_get_ratio<<std::endl<<
00061 "nadds="<<nadds<<std::endl<<
00062 "nsubs="<<nsubs<<std::endl<<
00063 "ncmps="<<ncmps<<std::endl<<
00064 "nmuls="<<nmuls<<std::endl<<
00065 "ngets="<<ngets<<std::endl<<
00066 "ndivs="<<m_ndivs<<std::endl<<
00067 "nconversions="<<m_nconversions<<std::endl
00068 ;
00069 }
00070 #else
00071 void
00072 HighPrecision::PrintStats (void)
00073 {}
00074 #endif
00075
00076
00077 const double HighPrecision::MAX_64 = 18446744073709551615.0;
00078
00079
00080 HighPrecision::HighPrecision (double value)
00081 {
00082 int64_t hi = (int64_t) floor (value);
00083 uint64_t lo = (uint64_t) ((value - floor (value)) * MAX_64);
00084 if (lo == 0)
00085 {
00086 m_isFast = true;
00087 m_fastValue = hi;
00088 return;
00089 }
00090 else
00091 {
00092 m_isFast = false;
00093 m_slowValue = _cairo_int64_to_int128 (hi);
00094 m_slowValue = _cairo_int128_lsl (m_slowValue, 64);
00095 cairo_int128_t clo = _cairo_uint128_to_int128 (_cairo_uint64_to_uint128 (lo));
00096 m_slowValue = _cairo_int128_add (m_slowValue, clo);
00097 }
00098 }
00099
00100 void
00101 HighPrecision::EnsureSlow (void)
00102 {
00103 if (m_isFast)
00104 {
00105 HP128INC (m_nconversions++);
00106 m_slowValue = _cairo_int64_to_int128 (m_fastValue);
00107 m_slowValue = _cairo_int128_lsl (m_slowValue, 64);
00108 m_isFast = false;
00109 }
00110 }
00111
00112 int64_t
00113 HighPrecision::SlowGetInteger (void) const
00114 {
00115 cairo_int128_t value = _cairo_int128_rsa (m_slowValue, 64);
00116 return _cairo_int128_to_int64 (value);
00117 }
00118
00119 double
00120 HighPrecision::SlowGetDouble (void) const
00121 {
00122 bool is_negative = _cairo_int128_negative (m_slowValue);
00123 cairo_int128_t value = is_negative?_cairo_int128_negate (m_slowValue):m_slowValue;
00124 cairo_int128_t hi = _cairo_int128_rsa (value, 64);
00125 cairo_uint128_t lo = _cairo_int128_sub (value, _cairo_uint128_lsl (hi, 64));
00126 double flo = _cairo_uint128_to_uint64 (lo);
00127 flo /= MAX_64;
00128 double retval = _cairo_uint128_to_uint64 (hi);
00129 retval += flo;
00130 retval *= is_negative?-1.0:1.0;
00131 return retval;
00132 }
00133 bool
00134 HighPrecision::SlowAdd (HighPrecision const &o)
00135 {
00136 EnsureSlow ();
00137 const_cast<HighPrecision &> (o).EnsureSlow ();
00138 m_slowValue = _cairo_int128_add (m_slowValue, o.m_slowValue);
00139 return false;
00140 }
00141 bool
00142 HighPrecision::SlowSub (HighPrecision const &o)
00143 {
00144 EnsureSlow ();
00145 const_cast<HighPrecision &> (o).EnsureSlow ();
00146 m_slowValue = _cairo_int128_sub (m_slowValue, o.m_slowValue);
00147 return false;
00148 }
00149 bool
00150 HighPrecision::SlowMul (HighPrecision const &o)
00151 {
00152 EnsureSlow ();
00153 const_cast<HighPrecision &> (o).EnsureSlow ();
00154 cairo_int128_t other = _cairo_int128_rsa (o.m_slowValue, 64);
00155 m_slowValue = _cairo_int128_mul (m_slowValue, other);
00156 return false;
00157 }
00158 bool
00159 HighPrecision::Div (HighPrecision const &o)
00160 {
00161 HP128INC (m_ndivs++);
00162 EnsureSlow ();
00163 const_cast<HighPrecision &> (o).EnsureSlow ();
00164 cairo_quorem128_t qr;
00165 qr = _cairo_int128_divrem (m_slowValue, o.m_slowValue);
00166 m_slowValue = _cairo_int128_lsl (qr.quo, 64);
00167
00168 cairo_int128_t div = o.m_slowValue;
00169 cairo_int128_t tmp;
00170 tmp = _cairo_int128_rsa (qr.rem, 64);
00171 cairo_int128_t zero = _cairo_int64_to_int128 (0);
00172 if (_cairo_int128_eq (tmp, zero))
00173 {
00174 qr.rem = _cairo_int128_lsl (qr.rem, 64);
00175 }
00176 else
00177 {
00178 div = _cairo_int128_rsa (div, 64);
00179 }
00180 qr = _cairo_int128_divrem (qr.rem, div);
00181 m_slowValue = _cairo_int128_add (m_slowValue, qr.quo);
00182 return false;
00183 }
00184 int
00185 HighPrecision::SlowCompare (HighPrecision const &o) const
00186 {
00187 const_cast<HighPrecision *> (this)->EnsureSlow ();
00188 const_cast<HighPrecision &> (o).EnsureSlow ();
00189 if (_cairo_int128_lt (m_slowValue, o.m_slowValue))
00190 {
00191 return -1;
00192 }
00193 else if (_cairo_int128_eq (m_slowValue, o.m_slowValue))
00194 {
00195 return 0;
00196 }
00197 else
00198 {
00199 return 1;
00200 }
00201 }
00202
00203 };
00204
00205
00206 #ifdef RUN_SELF_TESTS
00207 #include "ns3/test.h"
00208
00209 namespace ns3 {
00210
00211 class HighPrecision128Tests : public Test
00212 {
00213 public:
00214 HighPrecision128Tests ();
00215 virtual ~HighPrecision128Tests ();
00216 virtual bool RunTests (void);
00217 };
00218
00219 HighPrecision128Tests::HighPrecision128Tests ()
00220 : Test ("Int128")
00221 {}
00222 HighPrecision128Tests::~HighPrecision128Tests ()
00223 {}
00224
00225 #define CHECK_EXPECTED(v,expected) \
00226 { \
00227 if (v.GetInteger () != expected) \
00228 { \
00229 Failure () << "file="<<__FILE__<<", line="<<__LINE__<< \
00230 ", expected: "<<expected<<", got: "<< v.GetInteger ()<<std::endl; \
00231 result = false; \
00232 } \
00233 }
00234
00235 #define V(v) \
00236 HighPrecision (v, false)
00237
00238 bool
00239 HighPrecision128Tests::RunTests (void)
00240 {
00241 bool result = true;
00242
00243 HighPrecision a, b;
00244 a = HighPrecision (1, false);
00245 b = HighPrecision (1, false);
00246
00247 a.Sub (b);
00248 CHECK_EXPECTED (a, 0);
00249
00250 a = V (1);
00251 a.Sub (V(2));
00252 CHECK_EXPECTED (a, -1);
00253
00254 a = V (1);
00255 a.Sub (V(3));
00256 CHECK_EXPECTED (a, -2);
00257
00258 a = V (1);
00259 a.Sub (V(-1));
00260 CHECK_EXPECTED (a, 2);
00261
00262 a = V (1);
00263 a.Sub (V(-2));
00264 CHECK_EXPECTED (a, 3);
00265
00266 a = V (-3);
00267 a.Sub (V(-4));
00268 CHECK_EXPECTED (a, 1);
00269
00270 a = V (-2);
00271 a.Sub (V(3));
00272 CHECK_EXPECTED (a, -5);
00273
00274 a = V (1);
00275 a.Add (V(2));
00276 CHECK_EXPECTED (a, 3);
00277
00278 a = V (1);
00279 a.Add (V(-3));
00280 CHECK_EXPECTED (a, -2);
00281
00282 a = V (0);
00283 a.Add (V(0));
00284 CHECK_EXPECTED (a, 0);
00285
00286 a = V (0);
00287 a.Mul (V(0));
00288 CHECK_EXPECTED (a, 0);
00289 a = V (0);
00290 a.Mul (V(1));
00291 CHECK_EXPECTED (a, 0);
00292 a = V (0);
00293 a.Mul (V(-1));
00294 CHECK_EXPECTED (a, 0);
00295 a = V (1);
00296 a.Mul (V(0));
00297 CHECK_EXPECTED (a, 0);
00298 a = V (1);
00299 a.Mul (V(1));
00300 CHECK_EXPECTED (a, 1);
00301 a = V (1);
00302 a.Mul (V(-1));
00303 CHECK_EXPECTED (a, -1);
00304 a = V (-1);
00305 a.Mul (V(-1));
00306 CHECK_EXPECTED (a, 1);
00307
00308 a = V (0);
00309 a.Mul (V(1));
00310 CHECK_EXPECTED (a, 0);
00311 a = V (0);
00312 a.Mul (V(-1));
00313 CHECK_EXPECTED (a, 0);
00314 a = V (1);
00315 a.Mul (V(1));
00316 CHECK_EXPECTED (a, 1);
00317 a = V (1);
00318 a.Mul (V(-1));
00319 CHECK_EXPECTED (a, -1);
00320 a = V (-1);
00321 a.Mul (V(1));
00322 CHECK_EXPECTED (a, -1);
00323 a = V (-1);
00324 a.Mul (V(-1));
00325 CHECK_EXPECTED (a, 1);
00326
00327
00328
00329 a = V (2);
00330 a.Mul (V(3));
00331 a.Div (V(3));
00332 CHECK_EXPECTED (a, 2);
00333
00334
00335
00336
00337 a = V (2);
00338 a.Div (V(3));
00339 a.Mul (V(3));
00340 CHECK_EXPECTED (a, 1);
00341
00342
00343
00344
00345 a = V (2000000000);
00346 a.Div (V(3));
00347 a.Mul (V(3));
00348 CHECK_EXPECTED (a, 1999999999);
00349
00350
00351 a = HighPrecision (0.1);
00352 a.Div (HighPrecision (1.25));
00353 NS_TEST_ASSERT_EQUAL (a.GetDouble (), 0.08);
00354
00355
00356 return result;
00357 }
00358
00359 static HighPrecision128Tests g_int128Tests;
00360
00361 }
00362
00363 #endif