--- a/src/simulator/high-precision-128.cc Mon Aug 23 19:01:11 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,414 +0,0 @@
-#include "high-precision-128.h"
-#include "ns3/abort.h"
-#include "ns3/assert.h"
-#include <math.h>
-#ifdef COUNT_OPS
-#include <iostream>
-#endif
-
-namespace ns3 {
-
-#ifdef COUNT_OPS
-uint128_t HighPrecision::g_nAdd = 0;
-uint128_t HighPrecision::g_nMuli = 0;
-uint128_t HighPrecision::g_nMul = 0;
-uint128_t HighPrecision::g_nDiv = 0;
-uint128_t HighPrecision::g_nCmp = 0;
-HighPrecision::Printer HighPrecision::g_printer;
-HighPrecision::Printer::~Printer ()
-{
- std::cout << "add=" << (double)g_nAdd << " mul=" << (double)g_nMul << " div=" << (double)g_nDiv
- << " muli=" << (double)g_nMuli << " cmp=" << (double)g_nCmp;
-}
-#endif
-
-#define OUTPUT_SIGN(sa,sb,ua,ub) \
- ({bool negA, negB; \
- negA = sa < 0; \
- negB = sb < 0; \
- ua = negA?-sa:sa; \
- ub = negB?-sb:sb; \
- (negA && !negB) || (!negA && negB);})
-
-
-#define MASK_LO ((((uint128_t)1)<<64)-1)
-#define MASK_HI (~MASK_LO)
-HighPrecision::HighPrecision (int64_t high, uint64_t low)
-{
- bool is_negative = high<0;
- m_value = is_negative?-high:high;
- m_value <<= 64;
- m_value += low;
- m_value = is_negative?-m_value:m_value;
-}
-int64_t
-HighPrecision::GetHigh (void) const
-{
- return GetInteger ();
-}
-uint64_t
-HighPrecision::GetLow (void) const
-{
- bool negative = m_value < 0;
- int128_t v = negative?-m_value:m_value;
- int128_t low = v & MASK_LO;
- uint64_t retval = low;
- return retval;
-}
-
-void
-HighPrecision::Mul (HighPrecision const &o)
-{
- bool negResult;
- uint128_t a, b;
- negResult = OUTPUT_SIGN (m_value, o.m_value, a, b);
- int128_t result = Umul (a, b);
- // add the sign to the result
- result = negResult ? -result : result;
- m_value = result;
-}
-
-uint128_t
-HighPrecision::Umul (uint128_t a, uint128_t b)
-{
- INC_MUL;
- uint128_t aL = a & MASK_LO;
- uint128_t bL = b & MASK_LO;
- uint128_t aH = (a >> 64) & MASK_LO;
- uint128_t bH = (b >> 64) & MASK_LO;
-
- uint128_t result;
- uint128_t hiPart,loPart,midPart;
-
- // Multiplying (a.h 2^64 + a.l) x (b.h 2^64 + b.l) =
- // 2^128 a.h b.h + 2^64*(a.h b.l+b.h a.l) + a.l b.l
- // get the low part a.l b.l
- // multiply the fractional part
- loPart = aL * bL;
- // compute the middle part 2^64*(a.h b.l+b.h a.l)
- midPart = aL * bH + aH * bL;
- // truncate the low part
- result = (loPart >> 64) + (midPart & MASK_LO);
- // compute the high part 2^128 a.h b.h
- hiPart = aH * bH;
- // truncate the high part and only use the low part
- result |= ((hiPart & MASK_LO) << 64) + (midPart & MASK_HI);
- // if the high part is not zero, put a warning
- NS_ABORT_MSG_IF ((hiPart & MASK_HI) != 0,
- "High precision 128 bits multiplication error: multiplication overflow.");
- return result;
-}
-void
-HighPrecision::Div (HighPrecision const &o)
-{
- bool negResult;
- uint128_t a, b;
- negResult = OUTPUT_SIGN (m_value, o.m_value, a, b);
- int128_t result = Divu (a, b);
- result = negResult ? -result:result;
- m_value = result;
-}
-
-uint128_t
-HighPrecision::Divu (uint128_t a, uint128_t b)
-{
- INC_DIV;
- uint128_t quo = a / b;
- uint128_t rem = (a % b);
- uint128_t result = quo << 64;
- // Now, manage the remainder
- uint128_t tmp = rem >> 64;
- uint128_t div;
- if (tmp == 0)
- {
- rem = rem << 64;
- div = b;
- }
- else
- {
- rem = rem;
- div = b >> 64;
- }
- quo = rem / div;
- result = result + quo;
- return result;
-}
-
-void
-HighPrecision::MulByInvert (const HighPrecision &o)
-{
- bool negResult = m_value < 0;
- uint128_t a = negResult?-m_value:m_value;
- uint128_t result = UmulByInvert (a, o.m_value);
-
- m_value = negResult?-result:result;
-}
-uint128_t
-HighPrecision::UmulByInvert (uint128_t a, uint128_t b)
-{
- INC_MULI;
- uint128_t result, ah, bh, al, bl;
- uint128_t hi, mid;
- ah = a >> 64;
- bh = b >> 64;
- al = a & MASK_LO;
- bl = b & MASK_LO;
- hi = ah * bh;
- mid = ah * bl + al * bh;
- mid >>= 64;
- result = ah * bh + mid;
- return result;
-}
-HighPrecision
-HighPrecision::Invert (uint64_t v)
-{
- NS_ASSERT (v > 1);
- uint128_t a;
- a = 1;
- a <<= 64;
- HighPrecision result;
- result.m_value = Divu (a, v);
- HighPrecision tmp = HighPrecision (v, false);
- tmp.MulByInvert (result);
- if (tmp.GetInteger () != 1)
- {
- result.m_value += 1;
- }
- return result;
-}
-
-static uint8_t MostSignificantDigit (uint64_t value)
-{
- uint8_t n = 0;
- do
- {
- n++;
- value /= 10;
- } while (value != 0);
- return n;
-}
-
-static uint128_t PowerOfTen (uint8_t n)
-{
- uint128_t retval = 1;
- while (n > 0)
- {
- retval *= 10;
- n--;
- }
- return retval;
-}
-
-std::ostream &operator << (std::ostream &os, const HighPrecision &hp)
-{
- int64_t hi = hp.GetHigh ();
- os << ((hi<0)?"-":"+") << ((hi<0)?-hi:hi) << ".";
- uint128_t low = hp.GetLow ();
- uint8_t msd = MostSignificantDigit (~((uint64_t)0));
- do
- {
- msd--;
- uint128_t pow = PowerOfTen (msd);
- uint8_t digit = low / pow;
- NS_ASSERT (digit < 10);
- os << (uint16_t) digit;
- low -= digit * pow;
- } while (msd > 0 && low > 0);
- return os;
-}
-
-static uint64_t ReadDigits (std::string str)
-{
- const char *buf = str.c_str ();
- uint64_t retval = 0;
- while (*buf != 0)
- {
- retval *= 10;
- retval += *buf - 0x30;
- buf++;
- }
- return retval;
-}
-
-std::istream &operator >> (std::istream &is, HighPrecision &hp)
-{
- std::string str;
-
- is >> str;
- bool negative;
- // skip heading spaces
- std::string::size_type cur;
- cur = str.find_first_not_of (" ");
- std::string::size_type next;
- // first, remove the sign.
- next = str.find ("-", cur);
- if (next != std::string::npos)
- {
- negative = true;
- next++;
- }
- else
- {
- next = str.find ("+", cur);
- if (next != std::string::npos)
- {
- next++;
- }
- else
- {
- next = cur;
- }
- negative = false;
- }
- cur = next;
- int64_t hi;
- uint64_t lo;
- next = str.find(".", cur);
- if (next != std::string::npos)
- {
- hi = ReadDigits (str.substr (cur, next-cur));
- lo = ReadDigits (str.substr (next+1, str.size()-(next+1)));
- }
- else
- {
- hi = ReadDigits (str.substr (cur, str.size ()-cur));
- lo = 0;
- }
- hi = negative?-hi:hi;
- hp = HighPrecision (hi, lo);
- return is;
-}
-
-} // namespace ns3
-
-#include "ns3/test.h"
-
-namespace ns3
-{
-
-class HpFracTestCase : public TestCase
-{
-public:
- HpFracTestCase ();
- virtual bool DoRun (void);
- void CheckFrac (int64_t hi, uint64_t lo);
-};
-
-void
-HpFracTestCase::CheckFrac (int64_t hi, uint64_t lo)
-{
- HighPrecision tmp = HighPrecision (hi,lo);
- NS_TEST_EXPECT_MSG_EQ (tmp.GetHigh (), hi,
- "High part does not match");
- NS_TEST_EXPECT_MSG_EQ (tmp.GetLow (), lo,
- "Low part does not match");
-}
-
-HpFracTestCase::HpFracTestCase ()
- : TestCase ("Check that we can manipulate the high and low part of every number")
-{
-}
-bool
-HpFracTestCase::DoRun (void)
-{
- CheckFrac (1, 0);
- CheckFrac (1, 1);
- CheckFrac (-1, 0);
- CheckFrac (-1, 1);
- return GetErrorStatus ();
-}
-
-
-class HpInputTestCase : public TestCase
-{
-public:
- HpInputTestCase ();
- virtual bool DoRun (void);
- void CheckString (std::string str, int64_t hi, uint64_t lo);
-};
-HpInputTestCase::HpInputTestCase ()
- : TestCase ("Check that we parse HighPrecision numbers as strings")
-{
-}
-void
-HpInputTestCase::CheckString (std::string str, int64_t hi, uint64_t lo)
-{
- std::istringstream iss;
- iss.str (str);
- HighPrecision hp;
- iss >> hp;
- NS_TEST_EXPECT_MSG_EQ (hp.GetHigh (), hi, "High parts do not match for input string " << str);
- NS_TEST_EXPECT_MSG_EQ (hp.GetLow (), lo, "Low parts do not match for input string " << str);
-}
-bool
-HpInputTestCase::DoRun (void)
-{
- CheckString ("1", 1, 0);
- CheckString ("+1", 1, 0);
- CheckString ("-1", -1, 0);
- CheckString ("1.0", 1, 0);
- CheckString ("+1.0", 1, 0);
- CheckString ("001.0", 1, 0);
- CheckString ("+001.0", 1, 0);
- CheckString ("020.0", 20, 0);
- CheckString ("+020.0", 20, 0);
- CheckString ("-1.0", -1, 0);
- CheckString ("-1.0000", -1, 0);
- CheckString ("1.0000000", 1, 0);
- CheckString ("1.08446744073709551615", 1, 8446744073709551615LL);
- CheckString ("-1.08446744073709551615", -1, 8446744073709551615LL);
-
- return GetErrorStatus ();
-}
-
-class HpInputOutputTestCase : public TestCase
-{
-public:
- HpInputOutputTestCase ();
- virtual bool DoRun (void);
- void CheckString (std::string str);
-};
-HpInputOutputTestCase::HpInputOutputTestCase ()
- : TestCase ("Check that we can roundtrip HighPrecision numbers as strings")
-{
-}
-void
-HpInputOutputTestCase::CheckString (std::string str)
-{
- std::istringstream iss;
- iss.str (str);
- HighPrecision hp;
- iss >> hp;
- std::ostringstream oss;
- oss << hp;
- NS_TEST_EXPECT_MSG_EQ (oss.str (), str, "Converted string does not match expected string");
-}
-bool
-HpInputOutputTestCase::DoRun (void)
-{
- CheckString ("+1.0");
- CheckString ("-1.0");
- CheckString ("+20.0");
- CheckString ("+1.08446744073709551615");
- CheckString ("-1.08446744073709551615");
- CheckString ("+1.18446744073709551615");
- CheckString ("-1.18446744073709551615");
-
- return GetErrorStatus ();
-}
-
-
-static class HighPrecision128TestSuite : public TestSuite
-{
-public:
- HighPrecision128TestSuite ()
- : TestSuite ("high-precision-128", UNIT)
- {
- AddTestCase (new HpFracTestCase ());
- AddTestCase (new HpInputTestCase ());
- //AddTestCase (new HpOutputTestCase ());
- AddTestCase (new HpInputOutputTestCase ());
- }
-} g_highPrecision128TestSuite;
-
-} // namespace ns3
--- a/src/simulator/high-precision-128.h Mon Aug 23 19:01:11 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2010 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef HIGH_PRECISION_128_H
-#define HIGH_PRECISION_128_H
-
-#include "ns3/simulator-config.h"
-#include <math.h>
-#include <stdint.h>
-#include <iostream>
-
-#define noCOUNT_OPS 1
-
-#if defined(HAVE___UINT128_T) and !defined(HAVE_UINT128_T)
-typedef __uint128_t uint128_t;
-typedef __int128_t int128_t;
-#endif
-
-#ifdef COUNT_OPS
-#define INC_ADD HighPrecision::g_nAdd++
-#define INC_SUB HighPrecision::g_nAdd++
-#define INC_MUL HighPrecision::g_nMul++
-#define INC_DIV HighPrecision::g_nDiv++
-#define INC_MULI HighPrecision::g_nMuli++
-#define INC_CMP HighPrecision::g_nCmp++
-#else
-#define INC_ADD
-#define INC_SUB
-#define INC_MUL
-#define INC_DIV
-#define INC_MULI
-#define INC_CMP
-#endif
-
-namespace ns3 {
-
-class HighPrecision
-{
-public:
- inline HighPrecision ();
- explicit HighPrecision (int64_t high, uint64_t low);
- explicit inline HighPrecision (int64_t value, bool dummy);
- explicit inline HighPrecision (double value);
-
- inline int64_t GetInteger (void) const;
- inline double GetDouble (void) const;
- inline void Add (HighPrecision const &o);
- inline void Sub (HighPrecision const &o);
- void Mul (HighPrecision const &o);
- void Div (HighPrecision const &o);
- void MulByInvert (const HighPrecision &o);
- static HighPrecision Invert (uint64_t v);
-
- inline int Compare (HighPrecision const &o) const;
- inline static HighPrecision Zero (void);
-
- int64_t GetHigh (void) const;
- uint64_t GetLow (void) const;
-private:
- static uint128_t UmulByInvert (uint128_t a, uint128_t b);
- static uint128_t Umul (uint128_t a, uint128_t b);
- static uint128_t Divu (uint128_t a, uint128_t b);
-
- int128_t m_value;
-
-#ifdef COUNT_OPS
- static uint128_t g_nAdd;
- static uint128_t g_nMuli;
- static uint128_t g_nMul;
- static uint128_t g_nDiv;
- static uint128_t g_nCmp;
- static struct Printer {
- ~Printer ();
- } g_printer;
-#endif
-};
-
-std::ostream &operator << (std::ostream &os, const HighPrecision &hp);
-std::istream &operator >> (std::istream &is, HighPrecision &hp);
-
-} // namespace ns3
-
-namespace ns3 {
-
-HighPrecision::HighPrecision ()
- : m_value (0)
-{}
-HighPrecision::HighPrecision (int64_t value, bool dummy)
- : m_value (value)
-{
- m_value <<= 64;
-}
-
-
-
-int64_t HighPrecision::GetInteger (void) const
-{
- bool negative = m_value < 0;
- int128_t v = negative?-m_value:m_value;
- v >>= 64;
- int64_t retval = v;
- return negative?-retval:retval;
-}
-
-void
-HighPrecision::Add (HighPrecision const &o)
-{
- INC_ADD;
- m_value += o.m_value;
-}
-void
-HighPrecision::Sub (HighPrecision const &o)
-{
- INC_SUB;
- m_value -= o.m_value;
-}
-
-int
-HighPrecision::Compare (HighPrecision const &o) const
-{
- INC_CMP;
- return (m_value < o.m_value)?-1:(m_value == o.m_value)?0:1;
-}
-
-HighPrecision
-HighPrecision::Zero (void)
-{
- return HighPrecision ();
-}
-
-#define HP128_MAX_64 18446744073709551615.0
-double
-HighPrecision::GetDouble (void) const
-{
- bool is_negative = m_value < 0;
- uint128_t value = is_negative ? -m_value:m_value;
- uint64_t hi = value >> 64;
- uint64_t lo = value;
- double flo = lo;
- flo /= HP128_MAX_64;
- double retval = hi;
- retval += flo;
- retval = is_negative ? -retval : retval;
- return retval;
-}
-HighPrecision::HighPrecision (double value)
-{
- bool is_negative = value < 0;
- value = is_negative?-value:value;
- double hi = floor (value);
- double lo = (value - hi) * HP128_MAX_64;
- m_value = (int128_t)hi;
- m_value <<= 64;
- m_value += (int128_t)lo;
- m_value = is_negative?-m_value:m_value;
-}
-#undef HP128_MAX_64
-
-} // namespace ns3
-
-#endif /* HIGH_PRECISION_128_H */
--- a/src/simulator/high-precision-cairo.cc Mon Aug 23 19:01:11 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,187 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "high-precision-cairo.h"
-#include "ns3/test.h"
-#include "ns3/abort.h"
-#include "ns3/assert.h"
-#include <math.h>
-#include <iostream>
-
-namespace ns3 {
-
-
-#define OUTPUT_SIGN(sa,sb,ua,ub) \
- ({bool negA, negB; \
- negA = _cairo_int128_negative (sa); \
- negB = _cairo_int128_negative (sb); \
- ua = _cairo_int128_to_uint128 (sa); \
- ub = _cairo_int128_to_uint128 (sb); \
- ua = negA ? _cairo_uint128_negate (ua) : ua; \
- ub = negB ? _cairo_uint128_negate (ub) : ub; \
- (negA && !negB) || (!negA && negB);})
-
-void
-HighPrecision::Mul (HighPrecision const &o)
-{
- cairo_uint128_t a, b, result;
- bool sign = OUTPUT_SIGN (m_value, o.m_value, a, b);
- result = Umul (a, b);
- m_value = sign ? _cairo_uint128_negate (result) : result;
-}
-
-
-/**
- * this function multiplies two 128 bits fractions considering
- * the high 64 bits as the integer part and the low 64 bits
- * as the fractional part. It takes into account the sign
- * of the operands to produce a signed 128 bits result.
- */
-cairo_uint128_t
-HighPrecision::Umul (cairo_uint128_t a, cairo_uint128_t b)
-{
- cairo_uint128_t result;
- cairo_uint128_t hiPart,loPart,midPart;
-
- // Multiplying (a.h 2^64 + a.l) x (b.h 2^64 + b.l) =
- // 2^128 a.h b.h + 2^64*(a.h b.l+b.h a.l) + a.l b.l
- // get the low part a.l b.l
- // multiply the fractional part
- loPart = _cairo_uint64x64_128_mul (a.lo, b.lo);
- // compute the middle part 2^64*(a.h b.l+b.h a.l)
- midPart = _cairo_uint128_add (_cairo_uint64x64_128_mul (a.lo, b.hi),
- _cairo_uint64x64_128_mul (a.hi, b.lo));
- // truncate the low part
- result.lo = _cairo_uint64_add (loPart.hi,midPart.lo);
- // compute the high part 2^128 a.h b.h
- hiPart = _cairo_uint64x64_128_mul (a.hi, b.hi);
- // truncate the high part and only use the low part
- result.hi = _cairo_uint64_add (hiPart.lo,midPart.hi);
- // if the high part is not zero, put a warning
- NS_ABORT_MSG_IF (hiPart.hi != 0,
- "High precision 128 bits multiplication error: multiplication overflow.");
- return result;
-}
-
-void
-HighPrecision::Div (HighPrecision const &o)
-{
- cairo_uint128_t a, b, result;
- bool sign = OUTPUT_SIGN (m_value, o.m_value, a, b);
- result = Udiv (a, b);
- m_value = sign ? _cairo_uint128_negate (result) : result;
-}
-
-cairo_uint128_t
-HighPrecision::Udiv (cairo_uint128_t a, cairo_uint128_t b)
-{
- cairo_uquorem128_t qr = _cairo_uint128_divrem (a, b);
- cairo_uint128_t result = _cairo_uint128_lsl (qr.quo, 64);
- // Now, manage the remainder
- cairo_uint128_t tmp = _cairo_uint128_rsl (qr.rem, 64);
- cairo_uint128_t zero = _cairo_uint64_to_uint128 (0);
- cairo_uint128_t rem, div;
- if (_cairo_uint128_eq (tmp, zero))
- {
- rem = _cairo_uint128_lsl (qr.rem, 64);
- div = b;
- }
- else
- {
- rem = qr.rem;
- div = _cairo_uint128_rsl (b, 64);
- }
- qr = _cairo_uint128_divrem (rem, div);
- result = _cairo_uint128_add (result, qr.quo);
- return result;
-}
-
-void
-HighPrecision::MulByInvert (const HighPrecision &o)
-{
- bool negResult = _cairo_int128_negative (m_value);
- cairo_uint128_t a = negResult?_cairo_int128_negate(m_value):m_value;
- cairo_uint128_t result = UmulByInvert (a, o.m_value);
-
- m_value = negResult?_cairo_int128_negate(result):result;
-}
-cairo_uint128_t
-HighPrecision::UmulByInvert (cairo_uint128_t a, cairo_uint128_t b)
-{
- cairo_uint128_t result;
- cairo_uint128_t hi, mid;
- hi = _cairo_uint64x64_128_mul (a.hi, b.hi);
- mid = _cairo_uint128_add (_cairo_uint64x64_128_mul (a.hi, b.lo),
- _cairo_uint64x64_128_mul (a.lo, b.hi));
- mid.lo = mid.hi;
- mid.hi = 0;
- result = _cairo_uint128_add (hi,mid);
- return result;
-}
-HighPrecision
-HighPrecision::Invert (uint64_t v)
-{
- NS_ASSERT (v > 1);
- cairo_uint128_t a, factor;
- a.hi = 1;
- a.lo = 0;
- factor.hi = 0;
- factor.lo = v;
- HighPrecision result;
- result.m_value = Udiv (a, factor);
- HighPrecision tmp = HighPrecision (v, false);
- tmp.MulByInvert (result);
- if (tmp.GetInteger () != 1)
- {
- cairo_uint128_t one = {1, 0};
- result.m_value = _cairo_uint128_add (result.m_value, one);
- }
- return result;
-}
-
-int64_t
-HighPrecision::GetHigh (void) const
-{
- NS_FATAL_ERROR ("XXX this function unavailable for high-precision-as-cairo; patch requested");
- return 0;
-}
-
-uint64_t
-HighPrecision::GetLow (void) const
-{
- NS_FATAL_ERROR ("XXX this function unavailable for high-precision-as-cairo; patch requested");
- return 0;
-}
-
-std::ostream &operator << (std::ostream &os, const HighPrecision &hp)
-{
- return os;
-}
-std::istream &operator >> (std::istream &is, HighPrecision &hp)
-{
- return is;
-}
-
-
-} // namespace ns3
-
-// include directly to allow optimizations within the compilation unit.
-extern "C" {
-#include "cairo-wideint.c"
-}
--- a/src/simulator/high-precision-cairo.h Mon Aug 23 19:01:11 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef HIGH_PRECISION_CAIRO_H
-#define HIGH_PRECISION_CAIRO_H
-
-#include <stdint.h>
-#include <math.h>
-#include <iostream>
-#include "cairo-wideint-private.h"
-
-/**
- * This file contains an implementation of the HighPrecision class.
- * Each instance of the Time class also contains an instance of this
- * class which is used to perform all the arithmetic operations of
- * the Time class.
- *
- * This code is a bit ugly with a lot of inline methods for speed:
- * profiling this code on anything but the simplest scenarios shows
- * that it is a big bottleneck if great care in its implementation
- * is not performed. My observations are that what dominates are
- * Division operations (there are really really super costly)
- * and Comparison operations (because there are typically a lot of
- * these in any complex timekeeping code).
- */
-
-namespace ns3 {
-
-class HighPrecision
-{
-public:
- inline HighPrecision ();
- explicit inline HighPrecision (int64_t value, bool dummy);
- explicit inline HighPrecision (double value);
-
- inline int64_t GetInteger (void) const;
- inline double GetDouble (void) const;
- inline void Add (HighPrecision const &o);
- inline void Sub (HighPrecision const &o);
- void Mul (HighPrecision const &o);
- void Div (HighPrecision const &o);
- void MulByInvert (const HighPrecision &o);
- static HighPrecision Invert (uint64_t v);
-
- inline int Compare (HighPrecision const &o) const;
- inline static HighPrecision Zero (void);
- int64_t GetHigh (void) const;
- uint64_t GetLow (void) const;
-private:
- static cairo_uint128_t Umul (cairo_uint128_t a, cairo_uint128_t b);
- static cairo_uint128_t Udiv (cairo_uint128_t a, cairo_uint128_t b);
- static cairo_uint128_t UmulByInvert (cairo_uint128_t a, cairo_uint128_t b);
- inline bool IsNegative (void) const;
-
- cairo_int128_t m_value;
-};
-
-std::ostream &operator << (std::ostream &os, const HighPrecision &hp);
-std::istream &operator >> (std::istream &is, HighPrecision &hp);
-
-
-} // namespace ns3
-
-namespace ns3 {
-
-HighPrecision::HighPrecision ()
-{
- m_value.hi = 0;
- m_value.lo = 0;
-}
-
-HighPrecision::HighPrecision (int64_t value, bool dummy)
-{
- m_value.hi = value;
- m_value.lo = 0;
-}
-
-bool
-HighPrecision::IsNegative (void) const
-{
- int64_t hi = m_value.hi;
- return hi < 0;
-}
-
-int64_t
-HighPrecision::GetInteger (void) const
-{
- return m_value.hi;
-}
-void
-HighPrecision::Add (HighPrecision const &o)
-{
- m_value.hi += o.m_value.hi;
- m_value.lo += o.m_value.lo;
- if (m_value.lo < o.m_value.lo)
- {
- m_value.hi++;
- }
-}
-void
-HighPrecision::Sub (HighPrecision const &o)
-{
- m_value.hi -= o.m_value.hi;
- m_value.lo -= o.m_value.lo;
- if (m_value.lo > o.m_value.lo)
- {
- m_value.hi--;
- }
-}
-int
-HighPrecision::Compare (HighPrecision const &o) const
-{
- HighPrecision tmp = *this;
- tmp.Sub (o);
- return tmp.IsNegative ()?-1:(tmp.m_value.hi == 0 && tmp.m_value.lo == 0)?0:1;
-}
-HighPrecision
-HighPrecision::Zero (void)
-{
- return HighPrecision ();
-}
-
-
-#define HPCAIRO_MAX_64 18446744073709551615.0
-double HighPrecision::GetDouble (void) const
-{
- bool is_negative = IsNegative ();
- cairo_int128_t value = is_negative ? _cairo_int128_negate (m_value) : m_value;
- double flo = value.lo;
- flo /= HPCAIRO_MAX_64;
- double retval = value.hi;
- retval += flo;
- retval = is_negative ? -retval: retval;
- return retval;
-}
-#undef HPCAIRO_MAX_64
-
-#define HPCAIRO_MAX_64 18446744073709551615.0
-HighPrecision::HighPrecision (double value)
-{
- double fhi = floor (value);
- int64_t hi = static_cast<int64_t> (fhi);
- uint64_t lo = (uint64_t) ((value - fhi) * HPCAIRO_MAX_64);
- m_value.hi = hi;
- m_value.lo = lo;
-}
-#undef HPCAIRO_MAX_64
-
-} // namespace ns3
-
-#endif /* HIGH_PRECISION_CAIRO_H */
--- a/src/simulator/high-precision-double.h Mon Aug 23 19:01:11 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef HIGH_PRECISION_DOUBLE_H
-#define HIGH_PRECISION_DOUBLE_H
-
-#include <math.h>
-#include "ns3/fatal-error.h"
-
-namespace ns3 {
-
-/**
- * Obviously, this implementation of the HighPrecision class does
- * not provide the 128 bits accuracy since it uses a an IEEE754 double
- * to store the value. It also does not report overflows.
- * So, it is a nice shortcut but in no way a complete solution.
- */
-
-class HighPrecision
-{
-public:
- inline HighPrecision ();
- explicit inline HighPrecision (int64_t value, bool dummy);
- explicit inline HighPrecision (double value);
-
- inline int64_t GetInteger (void) const;
- inline double GetDouble (void) const;
- inline void Add (HighPrecision const &o);
- inline void Sub (HighPrecision const &o);
- inline void Mul (HighPrecision const &o);
- inline void Div (HighPrecision const &o);
- inline void MulByInvert (const HighPrecision &o);
- inline static HighPrecision Invert (uint64_t v);
-
- inline int Compare (HighPrecision const &o) const;
- inline static HighPrecision Zero (void);
- inline int64_t GetHigh (void) const;
- inline uint64_t GetLow (void) const;
-
-private:
- double m_value;
-};
-
-inline std::ostream &operator << (std::ostream &os, const HighPrecision &hp);
-inline std::istream &operator >> (std::istream &is, HighPrecision &hp);
-
-} // namespace ns3
-
-namespace ns3 {
-
-HighPrecision::HighPrecision ()
- : m_value (0.0)
-{
-}
-
-HighPrecision::HighPrecision (int64_t value, bool dummy)
- : m_value ((double)value)
-{
-}
-
-HighPrecision::HighPrecision (double value)
- : m_value (value)
-{
-}
-
-int64_t
-HighPrecision::GetInteger (void) const
-{
- return (int64_t)floor (m_value);
-}
-
-double
-HighPrecision::GetDouble (void) const
-{
- return m_value;
-}
-void
-HighPrecision::Add (HighPrecision const &o)
-{
- m_value += o.m_value;
-}
-void
-HighPrecision::Sub (HighPrecision const &o)
-{
- m_value -= o.m_value;
-}
-void
-HighPrecision::Mul (HighPrecision const &o)
-{
- m_value *= o.m_value;
-}
-void
-HighPrecision::Div (HighPrecision const &o)
-{
- m_value /= o.m_value;
-}
-void
-HighPrecision::MulByInvert (const HighPrecision &o)
-{
- m_value *= o.m_value;
-}
-HighPrecision
-HighPrecision::Invert (uint64_t v)
-{
- return HighPrecision (1.0 / v);
-}
-
-int
-HighPrecision::Compare (HighPrecision const &o) const
-{
- return (m_value < o.m_value)?-1:(m_value == o.m_value)?0:1;
-}
-HighPrecision
-HighPrecision::Zero (void)
-{
- return HighPrecision (0,0);
-}
-
-int64_t
-HighPrecision::GetHigh (void) const
-{
- return GetInteger ();
-}
-
-uint64_t
-HighPrecision::GetLow (void) const
-{
- NS_FATAL_ERROR ("XXX this function unavailable for high-precision-as-double; patch requested");
- return 0;
-}
-
-std::ostream &operator << (std::ostream &os, const HighPrecision &hp)
-{
- // XXX stubbed out
- return os;
-}
-
-std::istream &operator >> (std::istream &is, HighPrecision &hp)
-{
- // XXX stubbed out
- return is;
-}
-
-
-} // namespace ns3
-
-#endif /* HIGH_PRECISION_DOUBLE_H */
--- a/src/simulator/high-precision.cc Mon Aug 23 19:01:11 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,363 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "high-precision.h"
-
-#include <cmath>
-#include "ns3/assert.h"
-
-
-namespace ns3 {
-
-HighPrecision Abs (HighPrecision const &value)
-{
- if (value.Compare (HighPrecision::Zero ()) <= 0)
- {
- HighPrecision v = HighPrecision::Zero ();
- v.Sub (value);
- return v;
- }
- else
- {
- return value;
- }
-}
-
-} /* namespace ns3 */
-
-#include "ns3/test.h"
-
-#define CHECK_EXPECTED(a,b) \
- NS_TEST_ASSERT_MSG_EQ (a.GetInteger (),b,"Arithmetic failure: " << (a.GetInteger ()) << "!=" << (b))
-
-#define V(v) \
- HighPrecision (v, false)
-
-namespace ns3 {
-
-class HpArithmeticTestCase : public TestCase
-{
-public:
- HpArithmeticTestCase ();
- virtual bool DoRun (void);
-};
-
-HpArithmeticTestCase::HpArithmeticTestCase ()
- : TestCase ("Check basic arithmetic operations")
-{
-}
-bool
-HpArithmeticTestCase::DoRun (void)
-{
- HighPrecision a, b;
- a = HighPrecision (1, false);
- b = HighPrecision (1, false);
-
- a.Sub (b);
- CHECK_EXPECTED (a, 0);
-
- a = V (1);
- a.Sub (V (2));
- CHECK_EXPECTED (a, -1);
-
- a = V (1);
- a.Sub (V (3));
- CHECK_EXPECTED (a, -2);
-
- a = V (1);
- a.Sub (V (-1));
- CHECK_EXPECTED (a, 2);
-
- a = V (1);
- a.Sub (V (-2));
- CHECK_EXPECTED (a, 3);
-
- a = V (-3);
- a.Sub (V (-4));
- CHECK_EXPECTED (a, 1);
-
- a = V (-2);
- a.Sub (V (3));
- CHECK_EXPECTED (a, -5);
-
- a = V (1);
- a.Add (V (2));
- CHECK_EXPECTED (a, 3);
-
- a = V (1);
- a.Add (V (-3));
- CHECK_EXPECTED (a, -2);
-
- a = V (0);
- a.Add (V (0));
- CHECK_EXPECTED (a, 0);
-
- a = V (0);
- a.Mul (V (0));
- CHECK_EXPECTED (a, 0);
- a = V (0);
- a.Mul (V (1));
- CHECK_EXPECTED (a, 0);
- a = V (0);
- a.Mul (V (-1));
- CHECK_EXPECTED (a, 0);
- a = V (1);
- a.Mul (V (0));
- CHECK_EXPECTED (a, 0);
- a = V (1);
- a.Mul (V (1));
- CHECK_EXPECTED (a, 1);
- a = V (1);
- a.Mul (V (-1));
- CHECK_EXPECTED (a, -1);
- a = V (-1);
- a.Mul (V (-1));
- CHECK_EXPECTED (a, 1);
-
- a = V (0);
- a.Mul (V (1));
- CHECK_EXPECTED (a, 0);
- a = V (0);
- a.Mul (V (-1));
- CHECK_EXPECTED (a, 0);
- a = V (1);
- a.Mul (V (1));
- CHECK_EXPECTED (a, 1);
- a = V (1);
- a.Mul (V (-1));
- CHECK_EXPECTED (a, -1);
- a = V (-1);
- a.Mul (V (1));
- CHECK_EXPECTED (a, -1);
- a = V (-1);
- a.Mul (V (-1));
- CHECK_EXPECTED (a, 1);
-
-
-
- a = V (2);
- a.Mul (V (3));
- a.Div (V (3));
- CHECK_EXPECTED (a, 2);
-
- // Below, the division loses precision because 2/3 is not
- // representable exactly in 64.64 integers. So, we got
- // something super close but the final rounding kills us.
- a = V (2);
- a.Div (V (3));
- a.Mul (V (3));
- CHECK_EXPECTED (a, 1);
-
- // The example below shows that we really do not lose
- // much precision internally: it is almost always the
- // final conversion which loses precision.
- a = V (2000000000);
- a.Div (V (3));
- a.Mul (V (3));
- CHECK_EXPECTED (a, 1999999999);
-
- return GetErrorStatus ();
-}
-
-class HpBug455TestCase : public TestCase
-{
-public:
- HpBug455TestCase ();
- virtual bool DoRun (void);
-};
-
-HpBug455TestCase::HpBug455TestCase ()
- : TestCase ("Test case for bug 455")
-{
-}
-bool
-HpBug455TestCase::DoRun (void)
-{
- HighPrecision a = HighPrecision (0.1);
- a.Div (HighPrecision (1.25));
- NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 0.08, "The original testcase");
- a = HighPrecision (0.5);
- a.Mul (HighPrecision (5));
- NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 2.5, "Simple test for multiplication");
- a = HighPrecision (-0.5);
- a.Mul (HighPrecision (5));
- NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -2.5, "Test sign, first operation negative");
- a = HighPrecision (-0.5);
- a.Mul (HighPrecision (-5));
- NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 2.5, "both operands negative");
- a = HighPrecision (0.5);
- a.Mul (HighPrecision (-5));
- NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -2.5, "only second operand negative");
-
- return GetErrorStatus ();
-}
-
-
-class HpBug863TestCase : public TestCase
-{
-public:
- HpBug863TestCase ();
- virtual bool DoRun (void);
-};
-
-HpBug863TestCase::HpBug863TestCase ()
- : TestCase ("Test case for bug 863")
-{
-}
-bool
-HpBug863TestCase::DoRun (void)
-{
- HighPrecision a = HighPrecision (0.9);
- a.Div (HighPrecision (1));
- NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 0.9, "The original testcase");
- a = HighPrecision (0.5);
- a.Div (HighPrecision (0.5));
- NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 1.0, "Simple test for division");
- a = HighPrecision (-0.5);
- NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -0.5, "Check that we actually convert doubles correctly");
- a.Div (HighPrecision (0.5));
- NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -1.0, "first argument negative");
- a = HighPrecision (0.5);
- a.Div (HighPrecision (-0.5));
- NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -1.0, "second argument negative");
- a = HighPrecision (-0.5);
- a.Div (HighPrecision (-0.5));
- NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 1.0, "both arguments negative");
-
- return GetErrorStatus ();
-}
-
-class HpCompareTestCase : public TestCase
-{
-public:
- HpCompareTestCase ();
- virtual bool DoRun (void);
-};
-
-HpCompareTestCase::HpCompareTestCase ()
- : TestCase ("Check basic compare operations")
-{
-}
-bool
-HpCompareTestCase::DoRun (void)
-{
- HighPrecision a, b;
-
- a = V (-1);
- b = V (1);
- NS_TEST_ASSERT_MSG_EQ (a.Compare (b), -1, "a is smaller than b");
- a = V (-1);
- b = V (-2);
- NS_TEST_ASSERT_MSG_EQ (a.Compare (b), 1, "a is bigger than b");
- a = V (-1);
- b = V (-1);
- NS_TEST_ASSERT_MSG_EQ (a.Compare (b), 0, "a is equal to b");
-
- a = V (1);
- b = V (-1);
- NS_TEST_ASSERT_MSG_EQ (a.Compare (b), 1, "a is bigger than b");
- a = V (1);
- b = V (2);
- NS_TEST_ASSERT_MSG_EQ (a.Compare (b), -1, "a is smaller than b");
- a = V (1);
- b = V (1);
- NS_TEST_ASSERT_MSG_EQ (a.Compare (b), 0, "a is equal to b");
-
- return GetErrorStatus ();
-}
-
-class HpInvertTestCase : public TestCase
-{
-public:
- HpInvertTestCase ();
- virtual bool DoRun (void);
-};
-
-HpInvertTestCase::HpInvertTestCase ()
- : TestCase ("Test case for invertion")
-{
-}
-
-bool
-HpInvertTestCase::DoRun (void)
-{
-#define TEST(factor) \
- do { \
- HighPrecision a; \
- a = HighPrecision::Invert (factor); \
- HighPrecision b = V (factor); \
- b.MulByInvert (a); \
- NS_TEST_ASSERT_MSG_EQ (b.GetInteger (), 1, \
- "x * 1/x should be 1 for x=" << factor); \
- HighPrecision c = V (1); \
- c.MulByInvert (a); \
- NS_TEST_ASSERT_MSG_EQ (c.GetInteger (), 0, \
- "1 * 1/x should be 0 for x=" << factor); \
- HighPrecision d = V (1); \
- d.Div (V(factor)); \
- NS_TEST_ASSERT_MSG_EQ (d.GetDouble (), c.GetDouble (), \
- "1 * 1/x should be equal to 1/x for x=" << factor); \
- HighPrecision e = V (-factor); \
- e.MulByInvert (a); \
- NS_TEST_ASSERT_MSG_EQ (e.GetInteger (), -1, \
- "-x * 1/x should be -1 for x=" << factor); \
- } while(false)
-
- TEST(2);
- TEST(3);
- TEST(4);
- TEST(5);
- TEST(6);
- TEST(10);
- TEST(99);
- TEST(100);
- TEST(1000);
- TEST(10000);
- TEST(100000);
- TEST(100000);
- TEST(1000000);
- TEST(10000000);
- TEST(100000000);
- TEST(1000000000);
- TEST(10000000000LL);
- TEST(100000000000LL);
- TEST(1000000000000LL);
- TEST(10000000000000LL);
- TEST(100000000000000LL);
- TEST(1000000000000000LL);
-#undef TEST
- return GetErrorStatus ();
-}
-
-
-static class HighPrecisionTestSuite : public TestSuite
-{
-public:
- HighPrecisionTestSuite ()
- : TestSuite ("high-precision", UNIT)
- {
- AddTestCase (new HpArithmeticTestCase ());
- AddTestCase (new HpBug455TestCase ());
- AddTestCase (new HpBug863TestCase ());
- AddTestCase (new HpCompareTestCase ());
- AddTestCase (new HpInvertTestCase ());
- }
-} g_highPrecisionTestSuite;
-
-} // namespace ns3
--- a/src/simulator/high-precision.h Mon Aug 23 19:01:11 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef HIGH_PRECISION_H
-#define HIGH_PRECISION_H
-
-#include <stdint.h>
-#include "ns3/simulator-config.h"
-
-#if defined (USE_HIGH_PRECISION_DOUBLE)
-#include "high-precision-double.h"
-#elif defined (USE_HIGH_PRECISION_128)
-#include "high-precision-128.h"
-#elif defined (USE_HIGH_PRECISION_CAIRO)
-#include "high-precision-cairo.h"
-#endif
-
-namespace ns3 {
-
-HighPrecision Abs (HighPrecision const &value);
-inline HighPrecision Max (HighPrecision const &a, HighPrecision const &b);
-inline HighPrecision Min (HighPrecision const &a, HighPrecision const &b);
-
-
-inline HighPrecision Max (HighPrecision const &a, HighPrecision const &b)
-{
- if (a.Compare (b) >= 0)
- {
- return a;
- }
- else
- {
- return b;
- }
-}
-inline HighPrecision Min (HighPrecision const &a, HighPrecision const &b)
-{
- if (a.Compare (b) <= 0)
- {
- return a;
- }
- else
- {
- return b;
- }
-}
-
-} /* namespace ns3 */
-
-#endif /* HIGH_PRECISION_H */
--- a/src/simulator/nstime.h Mon Aug 23 19:01:11 2010 -0700
+++ b/src/simulator/nstime.h Tue Aug 24 16:36:41 2010 +0200
@@ -26,7 +26,7 @@
#include <stdint.h>
#include <math.h>
#include <ostream>
-#include "high-precision.h"
+#include "uint64x64.h"
namespace ns3 {
@@ -127,7 +127,7 @@
*
* In general, it is thus a really bad idea to try to use time objects of a
* resolution higher than the global resolution controlled through
- * TimeBase::SetResolution. If you do need to use picoseconds, it's thus best
+ * Time::SetResolution. If you do need to use picoseconds, it's thus best
* to switch the global resolution to picoseconds to avoid nasty surprises.
*
* Another important issue to keep in mind is that if you increase the
@@ -175,9 +175,24 @@
inline Time(const Time &o)
: m_data (o.m_data)
{}
- explicit inline Time (const HighPrecision &data)
+ explicit inline Time (const uint64x64_t &data)
: m_data (data)
{}
+ explicit inline Time (double v)
+ : m_data (uint64x64_t (v))
+ {}
+ explicit inline Time (int v)
+ : m_data (uint64x64_t (v, 0))
+ {}
+ explicit inline Time (unsigned int v)
+ : m_data (uint64x64_t (v, 0))
+ {}
+ explicit inline Time (long int v)
+ : m_data (uint64x64_t (v, 0))
+ {}
+ explicit inline Time (unsigned long int v)
+ : m_data (uint64x64_t (v, 0))
+ {}
/**
* \brief String constructor
@@ -195,63 +210,47 @@
* occur.
* \param s The string to parse into a Time
*/
- Time (const std::string & s);
+ explicit Time (const std::string & s);
/**
* \return true if the time is zero, false otherwise.
*/
inline bool IsZero (void) const
{
- return m_data.Compare (HighPrecision::Zero ()) == 0;
+ return m_data == uint64x64_t ();
}
/**
* \return true if the time is negative or zero, false otherwise.
*/
inline bool IsNegative (void) const
{
- return m_data.Compare (HighPrecision::Zero ()) <= 0;
+ return m_data <= uint64x64_t ();
}
/**
* \return true if the time is positive or zero, false otherwise.
*/
inline bool IsPositive (void) const
{
- return m_data.Compare (HighPrecision::Zero ()) >= 0;
+ return m_data >= uint64x64_t ();
}
/**
* \return true if the time is strictly negative, false otherwise.
*/
inline bool IsStrictlyNegative (void) const
{
- return m_data.Compare (HighPrecision::Zero ()) < 0;
+ return m_data < uint64x64_t ();
}
/**
* \return true if the time is strictly positive, false otherwise.
*/
inline bool IsStrictlyPositive (void) const
{
- return m_data.Compare (HighPrecision::Zero ()) > 0;
+ return m_data > uint64x64_t ();
}
inline int Compare (const Time &o) const
{
- return m_data.Compare (o.m_data);
- }
-
- /**
- * This is really an internal method exported for the needs of
- * the implementation. Please, Do not try to use this method, ever.
- *
- * \return the ns3::HighPrecision object which holds the value
- * stored in this instance of Time type.
- */
- inline HighPrecision const &GetHighPrecision (void) const
- {
- return m_data;
- }
- inline HighPrecision *PeekHighPrecision (void)
- {
- return &m_data;
+ return (m_data < o.m_data)?-1:(m_data == o.m_data)?0:1;
}
/**
@@ -309,9 +308,17 @@
*/
inline int64_t GetTimeStep (void) const
{
- int64_t timeValue = m_data.GetInteger ();
+ int64_t timeValue = m_data.GetHigh ();
return timeValue;
}
+ inline double GetDouble (void) const
+ {
+ return m_data.GetDouble ();
+ }
+ inline int64_t GetInteger (void) const
+ {
+ return GetTimeStep ();
+ }
/**
@@ -342,9 +349,9 @@
if (info->fromMul)
{
value *= info->factor;
- return Time (HighPrecision (value, false));
+ return Time (uint64x64_t (value, 0));
}
- return From (HighPrecision (value, false), timeUnit);
+ return From (uint64x64_t (value, 0), timeUnit);
}
/**
* \param value to convert into a Time object
@@ -355,7 +362,7 @@
*/
inline static Time FromDouble (double value, enum Unit timeUnit)
{
- return From (HighPrecision (value), timeUnit);
+ return From (uint64x64_t (value), timeUnit);
}
/**
* \param time a Time object
@@ -367,7 +374,7 @@
inline static uint64_t ToInteger (const Time &time, enum Unit timeUnit)
{
struct Information *info = PeekInformation (timeUnit);
- uint64_t v = time.m_data.GetInteger ();
+ uint64_t v = time.m_data.GetHigh ();
if (info->toMul)
{
v *= info->factor;
@@ -396,8 +403,8 @@
bool toMul;
bool fromMul;
uint64_t factor;
- HighPrecision timeTo;
- HighPrecision timeFrom;
+ uint64x64_t timeTo;
+ uint64x64_t timeFrom;
};
struct Resolution
{
@@ -414,15 +421,15 @@
{
return &(PeekResolution ()->info[timeUnit]);
}
- static inline Time From (HighPrecision from, enum Unit timeUnit)
+ static inline Time From (uint64x64_t from, enum Unit timeUnit)
{
struct Information *info = PeekInformation (timeUnit);
// DO NOT REMOVE this temporary variable. It's here
// to work around a compiler bug in gcc 3.4
- HighPrecision tmp = from;
+ uint64x64_t tmp = from;
if (info->fromMul)
{
- tmp.Mul (info->timeFrom);
+ tmp *= info->timeFrom;
}
else
{
@@ -430,13 +437,13 @@
}
return Time (tmp);
}
- static inline HighPrecision To (const Time &time, enum Unit timeUnit)
+ static inline uint64x64_t To (const Time &time, enum Unit timeUnit)
{
struct Information *info = PeekInformation (timeUnit);
- HighPrecision tmp = time.GetHighPrecision ();
+ uint64x64_t tmp = time.m_data;
if (info->toMul)
{
- tmp.Mul (info->timeTo);
+ tmp *= info->timeTo;
}
else
{
@@ -448,86 +455,91 @@
static struct Resolution GetNsResolution (void);
static void SetResolution (enum Unit unit, struct Resolution *resolution);
- HighPrecision m_data;
+ friend bool operator == (const Time &lhs, const Time &rhs);
+ friend bool operator != (const Time &lhs, const Time &rhs);
+ friend bool operator <= (const Time &lhs, const Time &rhs);
+ friend bool operator >= (const Time &lhs, const Time &rhs);
+ friend bool operator < (const Time &lhs, const Time &rhs);
+ friend bool operator > (const Time &lhs, const Time &rhs);
+ friend Time operator + (const Time &lhs, const Time &rhs);
+ friend Time operator - (const Time &lhs, const Time &rhs);
+ friend Time operator * (const Time &lhs, const Time &rhs);
+ friend Time operator / (const Time &lhs, const Time &rhs);
+ friend Time &operator += (Time &lhs, const Time &rhs);
+ friend Time &operator -= (Time &lhs, const Time &rhs);
+ friend Time &operator *= (Time &lhs, const Time &rhs);
+ friend Time &operator /= (Time &lhs, const Time &rhs);
+ friend Time Abs (const Time &time);
+ friend Time Max (const Time &ta, const Time &tb);
+ friend Time Min (const Time &ta, const Time &tb);
+
+ uint64x64_t m_data;
};
inline bool
-operator == (Time const &lhs, Time const &rhs)
+operator == (const Time &lhs, const Time &rhs)
{
- return lhs.Compare (rhs) == 0;
+ return lhs.m_data == rhs.m_data;
}
inline bool
-operator != (Time const &lhs, Time const &rhs)
+operator != (const Time &lhs, const Time &rhs)
{
- return lhs.Compare (rhs) != 0;
+ return lhs.m_data != rhs.m_data;
}
inline bool
-operator <= (Time const &lhs, Time const &rhs)
+operator <= (const Time &lhs, const Time &rhs)
{
- return lhs.Compare (rhs) <= 0;
+ return lhs.m_data <= rhs.m_data;
}
inline bool
-operator >= (Time const &lhs, Time const &rhs)
+operator >= (const Time &lhs, const Time &rhs)
{
- return lhs.Compare (rhs) >= 0;
+ return lhs.m_data >= rhs.m_data;
}
inline bool
-operator < (Time const &lhs, Time const &rhs)
+operator < (const Time &lhs, const Time &rhs)
{
- return lhs.Compare (rhs) < 0;
+ return lhs.m_data < rhs.m_data;
}
inline bool
-operator > (Time const &lhs, Time const &rhs)
+operator > (const Time &lhs, const Time &rhs)
{
- return lhs.Compare (rhs) > 0;
+ return lhs.m_data > rhs.m_data;
}
-inline Time operator + (Time const &lhs, Time const &rhs)
+inline Time operator + (const Time &lhs, const Time &rhs)
{
- HighPrecision retval = lhs.GetHighPrecision ();
- retval.Add (rhs.GetHighPrecision ());
- return Time (retval);
+ return Time (lhs.m_data + rhs.m_data);
}
-inline Time operator - (Time const &lhs, Time const &rhs)
+inline Time operator - (const Time &lhs, const Time &rhs)
{
- HighPrecision retval = lhs.GetHighPrecision ();
- retval.Sub (rhs.GetHighPrecision ());
- return Time (retval);
+ return Time (lhs.m_data - rhs.m_data);
}
-inline Time operator * (Time const &lhs, Time const &rhs)
+inline Time operator * (const Time &lhs, const Time &rhs)
{
- HighPrecision retval = lhs.GetHighPrecision ();
- retval.Mul (rhs.GetHighPrecision ());
- return Time (retval);
+ return Time (lhs.m_data * rhs.m_data);
}
-inline Time operator / (Time const &lhs, Time const &rhs)
+inline Time operator / (const Time &lhs, const Time &rhs)
{
- NS_ASSERT (rhs.GetHighPrecision ().GetDouble () != 0);
- HighPrecision retval = lhs.GetHighPrecision ();
- retval.Div (rhs.GetHighPrecision ());
- return Time (retval);
+ return Time (lhs.m_data / rhs.m_data);
}
-inline Time &operator += (Time &lhs, Time const &rhs)
+inline Time &operator += (Time &lhs, const Time &rhs)
{
- HighPrecision *lhsv = lhs.PeekHighPrecision ();
- lhsv->Add (rhs.GetHighPrecision ());
+ lhs.m_data += rhs.m_data;
return lhs;
}
-inline Time &operator -= (Time &lhs, Time const &rhs)
+inline Time &operator -= (Time &lhs, const Time &rhs)
{
- HighPrecision *lhsv = lhs.PeekHighPrecision ();
- lhsv->Sub (rhs.GetHighPrecision ());
+ lhs.m_data -= rhs.m_data;
return lhs;
}
-inline Time &operator *= (Time &lhs, Time const &rhs)
+inline Time &operator *= (Time &lhs, const Time &rhs)
{
- HighPrecision *lhsv = lhs.PeekHighPrecision ();
- lhsv->Mul (rhs.GetHighPrecision ());
+ lhs.m_data *= rhs.m_data;
return lhs;
}
-inline Time &operator /= (Time &lhs, Time const &rhs)
+inline Time &operator /= (Time &lhs, const Time &rhs)
{
- HighPrecision *lhsv = lhs.PeekHighPrecision ();
- lhsv->Div (rhs.GetHighPrecision ());
+ lhs.m_data /= rhs.m_data;
return lhs;
}
@@ -538,9 +550,9 @@
* \param time the input value
* \returns the absolute value of the input value.
*/
-inline Time Abs (Time const &time)
+inline Time Abs (const Time &time)
{
- return Time (Abs (time.GetHighPrecision ()));
+ return Time ((time.m_data < uint64x64_t (0))?-time.m_data:time.m_data);
}
/**
* \anchor ns3-Time-Max
@@ -549,11 +561,9 @@
* \param tb the seconds value
* \returns the max of the two input values.
*/
-inline Time Max (Time const &ta, Time const &tb)
+inline Time Max (const Time &ta, const Time &tb)
{
- HighPrecision a = ta.GetHighPrecision ();
- HighPrecision b = tb.GetHighPrecision ();
- return Time (Max (a, b));
+ return Time ((ta.m_data < tb.m_data)?tb:ta);
}
/**
* \anchor ns3-Time-Min
@@ -562,11 +572,9 @@
* \param tb the seconds value
* \returns the min of the two input values.
*/
-inline Time Min (Time const &ta, Time const &tb)
+inline Time Min (const Time &ta, const Time &tb)
{
- HighPrecision a = ta.GetHighPrecision ();
- HighPrecision b = tb.GetHighPrecision ();
- return Time (Min (a, b));
+ return Time ((ta.m_data > tb.m_data)?tb:ta);
}
@@ -662,45 +670,10 @@
// internal function not publicly documented
inline Time TimeStep (uint64_t ts)
{
- return Time (HighPrecision (ts, false));
+ return Time (uint64x64_t (ts, 0));
}
-class Scalar
-{
-public:
- inline Scalar ()
- : m_v (0.0)
- {}
- explicit inline Scalar (double v)
- : m_v (v)
- {}
- explicit inline Scalar (uint32_t v)
- : m_v (v)
- {}
- explicit inline Scalar (int32_t v)
- : m_v (v)
- {}
- explicit inline Scalar (uint64_t v)
- : m_v (v)
- {}
- explicit inline Scalar (int64_t v)
- : m_v (v)
- {}
- inline Scalar (Time t)
- : m_v (t.GetHighPrecision ().GetDouble ())
- {}
- inline operator Time ()
- {
- return Time (HighPrecision (m_v));
- }
- inline double GetDouble (void) const
- {
- return m_v;
- }
-private:
- double m_v;
-};
-
+typedef Time Scalar;
typedef Time TimeInvert;
typedef Time TimeSquare;
--- a/src/simulator/time.cc Mon Aug 23 19:01:11 2010 -0700
+++ b/src/simulator/time.cc Tue Aug 24 16:36:41 2010 +0200
@@ -26,14 +26,11 @@
#include "ns3/string.h"
#include "ns3/object.h"
#include "ns3/config.h"
-#include "ns3/log.h"
#include <math.h>
#include <sstream>
namespace ns3 {
-NS_LOG_COMPONENT_DEFINE("Time");
-
Time::Time (const std::string& s)
{
std::string::size_type n = s.find_first_not_of ("0123456789.");
@@ -100,7 +97,6 @@
void
Time::SetResolution (enum Unit unit, struct Resolution *resolution)
{
- NS_LOG_FUNCTION (unit << resolution);
int8_t power [LAST] = {15, 12, 9, 6, 3, 0};
for (int i = 0; i < Time::LAST; i++)
{
@@ -110,30 +106,26 @@
info->factor = factor;
if (shift == 0)
{
- info->timeFrom = HighPrecision (1, false);
- info->timeTo = HighPrecision (1, false);
+ info->timeFrom = uint64x64_t (1, 0);
+ info->timeTo = uint64x64_t (1, 0);
info->toMul = true;
info->fromMul = true;
}
else if (shift > 0)
{
- info->timeFrom = HighPrecision (factor, false);
- info->timeTo = HighPrecision::Invert (factor);
+ info->timeFrom = uint64x64_t (factor, 0);
+ info->timeTo = uint64x64_t::Invert (factor);
info->toMul = false;
info->fromMul = true;
}
else
{
NS_ASSERT (shift < 0);
- info->timeFrom = HighPrecision::Invert (factor);
- info->timeTo = HighPrecision (factor, false);
+ info->timeFrom = uint64x64_t::Invert (factor);
+ info->timeTo = uint64x64_t (factor, 0);
info->toMul = true;
info->fromMul = false;
}
- NS_LOG_DEBUG ("i=" << i <<
- " shift=" << shift <<
- " from=" << info->timeFrom <<
- " to=" << info->timeTo);
}
resolution->unit = unit;
}
@@ -173,7 +165,7 @@
unit = "unreachable";
break;
}
- uint64_t v = Time::ToInteger (time, Time::GetResolution ());
+ double v = Time::ToDouble (time, Time::GetResolution ());
os << v << unit;
return os;
}
@@ -208,7 +200,9 @@
bool Bug863TestCase::DoRun (void)
{
- Scalar result = Scalar (0.9) / Scalar (1.0);
+ Scalar a = Scalar (0.9);
+ Scalar b = Scalar (1.0);
+ Scalar result = a / b;
NS_TEST_ASSERT_MSG_EQ ((result == Scalar (0.9)), true, "Invalid arithmetic result");
return false;
}
@@ -260,44 +254,6 @@
Time::SetResolution (m_originalResolution);
}
-class ArithTestCase : public TestCase
-{
-public:
- ArithTestCase ();
-private:
- virtual bool DoRun (void);
-};
-
-ArithTestCase::ArithTestCase ()
- : TestCase ("check arithmetic operators")
-{
-}
-bool
-ArithTestCase::DoRun (void)
-{
- Time a, b, c;
- c = a + b;
- c = a * b;
- c = a / Seconds (1.0);
- c = a - b;
- c += a;
- c -= a;
- c /= Seconds (1.0);
- c *= a;
- bool x;
- x = a < b;
- x = a > b;
- x = a <= b;
- x = a >= b;
- x = a == b;
- x = a != b;
- //a = 1.0;
- //a = 1;
- return false;
-}
-
-
-
static class TimeTestSuite : public TestSuite
{
public:
@@ -306,7 +262,6 @@
{
AddTestCase (new Bug863TestCase ());
AddTestCase (new TimeSimpleTestCase (Time::US));
- AddTestCase (new ArithTestCase ());
}
} g_timeTestSuite;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/uint64x64-128.cc Tue Aug 24 16:36:41 2010 +0200
@@ -0,0 +1,138 @@
+#include "uint64x64-128.h"
+#include "ns3/abort.h"
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+#define OUTPUT_SIGN(sa,sb,ua,ub) \
+ ({bool negA, negB; \
+ negA = sa < 0; \
+ negB = sb < 0; \
+ ua = negA?-sa:sa; \
+ ub = negB?-sb:sb; \
+ (negA && !negB) || (!negA && negB);})
+
+
+#define MASK_LO ((((int128_t)1)<<64)-1)
+#define MASK_HI (~MASK_LO)
+
+void
+uint64x64_t::Mul (uint64x64_t const &o)
+{
+ bool negResult;
+ uint128_t a, b;
+ negResult = OUTPUT_SIGN (_v, o._v, a, b);
+ int128_t result = Umul (a, b);
+ // add the sign to the result
+ result = negResult ? -result : result;
+ _v = result;
+}
+
+uint128_t
+uint64x64_t::Umul (uint128_t a, uint128_t b)
+{
+ uint128_t aL = a & MASK_LO;
+ uint128_t bL = b & MASK_LO;
+ uint128_t aH = (a >> 64) & MASK_LO;
+ uint128_t bH = (b >> 64) & MASK_LO;
+
+ uint128_t result;
+ uint128_t hiPart,loPart,midPart;
+
+ // Multiplying (a.h 2^64 + a.l) x (b.h 2^64 + b.l) =
+ // 2^128 a.h b.h + 2^64*(a.h b.l+b.h a.l) + a.l b.l
+ // get the low part a.l b.l
+ // multiply the fractional part
+ loPart = aL * bL;
+ // compute the middle part 2^64*(a.h b.l+b.h a.l)
+ midPart = aL * bH + aH * bL;
+ // truncate the low part
+ result = (loPart >> 64) + (midPart & MASK_LO);
+ // compute the high part 2^128 a.h b.h
+ hiPart = aH * bH;
+ // truncate the high part and only use the low part
+ result |= ((hiPart & MASK_LO) << 64) + (midPart & MASK_HI);
+ // if the high part is not zero, put a warning
+ NS_ABORT_MSG_IF ((hiPart & MASK_HI) != 0,
+ "High precision 128 bits multiplication error: multiplication overflow.");
+ return result;
+}
+void
+uint64x64_t::Div (uint64x64_t const &o)
+{
+ bool negResult;
+ uint128_t a, b;
+ negResult = OUTPUT_SIGN (_v, o._v, a, b);
+ int128_t result = Divu (a, b);
+ result = negResult ? -result:result;
+ _v = result;
+}
+
+uint128_t
+uint64x64_t::Divu (uint128_t a, uint128_t b)
+{
+ uint128_t quo = a / b;
+ uint128_t rem = (a % b);
+ uint128_t result = quo << 64;
+ // Now, manage the remainder
+ uint128_t tmp = rem >> 64;
+ uint128_t div;
+ if (tmp == 0)
+ {
+ rem = rem << 64;
+ div = b;
+ }
+ else
+ {
+ rem = rem;
+ div = b >> 64;
+ }
+ quo = rem / div;
+ result = result + quo;
+ return result;
+}
+
+void
+uint64x64_t::MulByInvert (const uint64x64_t &o)
+{
+ bool negResult = _v < 0;
+ uint128_t a = negResult?-_v:_v;
+ uint128_t result = UmulByInvert (a, o._v);
+
+ _v = negResult?-result:result;
+}
+uint128_t
+uint64x64_t::UmulByInvert (uint128_t a, uint128_t b)
+{
+ uint128_t result, ah, bh, al, bl;
+ uint128_t hi, mid;
+ ah = a >> 64;
+ bh = b >> 64;
+ al = a & MASK_LO;
+ bl = b & MASK_LO;
+ hi = ah * bh;
+ mid = ah * bl + al * bh;
+ mid >>= 64;
+ result = ah * bh + mid;
+ return result;
+}
+uint64x64_t
+uint64x64_t::Invert (uint64_t v)
+{
+ NS_ASSERT (v > 1);
+ uint128_t a;
+ a = 1;
+ a <<= 64;
+ uint64x64_t result;
+ result._v = Divu (a, v);
+ uint64x64_t tmp = uint64x64_t (v, false);
+ tmp.MulByInvert (result);
+ if (tmp.GetHigh () != 1)
+ {
+ result._v += 1;
+ }
+ return result;
+}
+
+} // namespace ns3
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/uint64x64-128.h Tue Aug 24 16:36:41 2010 +0200
@@ -0,0 +1,197 @@
+#ifndef UINT64X64_128_H
+#define UINT64X64_128_H
+
+#include "ns3/simulator-config.h"
+#include <stdint.h>
+#include <math.h>
+
+#if defined(HAVE___UINT128_T) and !defined(HAVE_UINT128_T)
+typedef __uint128_t uint128_t;
+typedef __int128_t int128_t;
+#endif
+
+namespace ns3 {
+
+#define HP128_MAX_64 18446744073709551615.0
+#define HP128_MASK_LO ((((int128_t)1)<<64)-1)
+
+class uint64x64_t
+{
+public:
+ inline uint64x64_t ()
+ : _v (0)
+ {}
+ explicit inline uint64x64_t (double value)
+ {
+ bool is_negative = value < 0;
+ value = is_negative?-value:value;
+ double hi = floor (value);
+ double lo = (value - hi) * HP128_MAX_64;
+ _v = (int128_t)hi;
+ _v <<= 64;
+ _v += (int128_t)lo;
+ _v = is_negative?-_v:_v;
+ }
+ explicit inline uint64x64_t (int v)
+ : _v (v)
+ {
+ _v <<= 64;
+ }
+ explicit inline uint64x64_t (long int v)
+ : _v (v)
+ {
+ _v <<= 64;
+ }
+ explicit inline uint64x64_t (long long int v)
+ : _v (v)
+ {
+ _v <<= 64;
+ }
+ explicit inline uint64x64_t (int64_t hi, uint64_t lo)
+ {
+ bool is_negative = hi<0;
+ _v = is_negative?-hi:hi;
+ _v <<= 64;
+ _v += lo;
+ _v = is_negative?-_v:_v;
+ }
+
+ inline uint64x64_t (const uint64x64_t &o)
+ : _v (o._v) {}
+ inline uint64x64_t &operator = (const uint64x64_t &o)
+ {
+ _v = o._v;
+ return *this;
+ }
+
+ inline double GetDouble (void) const
+ {
+ bool is_negative = _v < 0;
+ uint128_t value = is_negative ? -_v:_v;
+ uint64_t hi = value >> 64;
+ uint64_t lo = value;
+ double flo = lo;
+ flo /= HP128_MAX_64;
+ double retval = hi;
+ retval += flo;
+ retval = is_negative ? -retval : retval;
+ return retval;
+ }
+ inline int64_t GetHigh (void) const
+ {
+ bool negative = _v < 0;
+ int128_t v = negative?-_v:_v;
+ v >>= 64;
+ int64_t retval = v;
+ return negative?-retval:retval;
+ }
+ inline uint64_t GetLow (void) const
+ {
+ bool negative = _v < 0;
+ int128_t v = negative?-_v:_v;
+ int128_t low = v & HP128_MASK_LO;
+ uint64_t retval = low;
+ return retval;
+ }
+#undef HP128_MAX_64
+#undef HP128_MASK_LO
+
+ void MulByInvert (const uint64x64_t &o);
+
+ static uint64x64_t Invert (uint64_t v);
+
+private:
+ friend bool operator == (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator != (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator <= (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator >= (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator < (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator > (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator += (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator -= (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator *= (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator /= (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator + (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator - (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator * (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator / (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator + (const uint64x64_t &lhs);
+ friend uint64x64_t operator - (const uint64x64_t &lhs);
+ friend uint64x64_t operator ! (const uint64x64_t &lhs);
+ void Mul (const uint64x64_t &o);
+ void Div (const uint64x64_t &o);
+ static uint128_t UmulByInvert (uint128_t a, uint128_t b);
+ static uint128_t Umul (uint128_t a, uint128_t b);
+ static uint128_t Divu (uint128_t a, uint128_t b);
+ inline uint64x64_t (int128_t v)
+ : _v (v) {}
+
+ int128_t _v;
+};
+
+inline bool operator == (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v == rhs._v;
+}
+
+inline bool operator != (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v != rhs._v;
+}
+
+inline bool operator < (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v < rhs._v;
+}
+inline bool operator <= (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v <= rhs._v;
+}
+
+inline bool operator >= (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v >= rhs._v;
+}
+inline bool operator > (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v > rhs._v;
+}
+inline uint64x64_t &operator += (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ lhs._v += rhs._v;
+ return lhs;
+}
+inline uint64x64_t &operator -= (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ lhs._v -= rhs._v;
+ return lhs;
+}
+inline uint64x64_t &operator *= (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ lhs.Mul (rhs);
+ return lhs;
+}
+inline uint64x64_t &operator /= (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ lhs.Div (rhs);
+ return lhs;
+}
+
+inline uint64x64_t operator + (const uint64x64_t &lhs)
+{
+ return lhs;
+}
+
+inline uint64x64_t operator - (const uint64x64_t &lhs)
+{
+ return uint64x64_t (-lhs._v);
+}
+
+inline uint64x64_t operator ! (const uint64x64_t &lhs)
+{
+ return uint64x64_t (!lhs._v);
+}
+
+} // namespace ns3
+
+#endif /* UINT64X64_128_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/uint64x64-cairo.cc Tue Aug 24 16:36:41 2010 +0200
@@ -0,0 +1,162 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "uint64x64-cairo.h"
+#include "ns3/test.h"
+#include "ns3/abort.h"
+#include "ns3/assert.h"
+#include <math.h>
+#include <iostream>
+
+namespace ns3 {
+
+#define OUTPUT_SIGN(sa,sb,ua,ub) \
+ ({bool negA, negB; \
+ negA = _cairo_int128_negative (sa); \
+ negB = _cairo_int128_negative (sb); \
+ ua = _cairo_int128_to_uint128 (sa); \
+ ub = _cairo_int128_to_uint128 (sb); \
+ ua = negA ? _cairo_uint128_negate (ua) : ua; \
+ ub = negB ? _cairo_uint128_negate (ub) : ub; \
+ (negA && !negB) || (!negA && negB);})
+
+void
+uint64x64_t::Mul (uint64x64_t const &o)
+{
+ cairo_uint128_t a, b, result;
+ bool sign = OUTPUT_SIGN (_v, o._v, a, b);
+ result = Umul (a, b);
+ _v = sign ? _cairo_uint128_negate (result) : result;
+}
+
+/**
+ * this function multiplies two 128 bits fractions considering
+ * the high 64 bits as the integer part and the low 64 bits
+ * as the fractional part. It takes into account the sign
+ * of the operands to produce a signed 128 bits result.
+ */
+cairo_uint128_t
+uint64x64_t::Umul (cairo_uint128_t a, cairo_uint128_t b)
+{
+ cairo_uint128_t result;
+ cairo_uint128_t hiPart,loPart,midPart;
+
+ // Multiplying (a.h 2^64 + a.l) x (b.h 2^64 + b.l) =
+ // 2^128 a.h b.h + 2^64*(a.h b.l+b.h a.l) + a.l b.l
+ // get the low part a.l b.l
+ // multiply the fractional part
+ loPart = _cairo_uint64x64_128_mul (a.lo, b.lo);
+ // compute the middle part 2^64*(a.h b.l+b.h a.l)
+ midPart = _cairo_uint128_add (_cairo_uint64x64_128_mul (a.lo, b.hi),
+ _cairo_uint64x64_128_mul (a.hi, b.lo));
+ // truncate the low part
+ result.lo = _cairo_uint64_add (loPart.hi,midPart.lo);
+ // compute the high part 2^128 a.h b.h
+ hiPart = _cairo_uint64x64_128_mul (a.hi, b.hi);
+ // truncate the high part and only use the low part
+ result.hi = _cairo_uint64_add (hiPart.lo,midPart.hi);
+ // if the high part is not zero, put a warning
+ NS_ABORT_MSG_IF (hiPart.hi != 0,
+ "High precision 128 bits multiplication error: multiplication overflow.");
+ return result;
+}
+
+void
+uint64x64_t::Div (uint64x64_t const &o)
+{
+ cairo_uint128_t a, b, result;
+ bool sign = OUTPUT_SIGN (_v, o._v, a, b);
+ result = Udiv (a, b);
+ _v = sign ? _cairo_uint128_negate (result) : result;
+}
+
+cairo_uint128_t
+uint64x64_t::Udiv (cairo_uint128_t a, cairo_uint128_t b)
+{
+ cairo_uquorem128_t qr = _cairo_uint128_divrem (a, b);
+ cairo_uint128_t result = _cairo_uint128_lsl (qr.quo, 64);
+ // Now, manage the remainder
+ cairo_uint128_t tmp = _cairo_uint128_rsl (qr.rem, 64);
+ cairo_uint128_t zero = _cairo_uint64_to_uint128 (0);
+ cairo_uint128_t rem, div;
+ if (_cairo_uint128_eq (tmp, zero))
+ {
+ rem = _cairo_uint128_lsl (qr.rem, 64);
+ div = b;
+ }
+ else
+ {
+ rem = qr.rem;
+ div = _cairo_uint128_rsl (b, 64);
+ }
+ qr = _cairo_uint128_divrem (rem, div);
+ result = _cairo_uint128_add (result, qr.quo);
+ return result;
+}
+
+void
+uint64x64_t::MulByInvert (const uint64x64_t &o)
+{
+ bool negResult = _cairo_int128_negative (_v);
+ cairo_uint128_t a = negResult?_cairo_int128_negate(_v):_v;
+ cairo_uint128_t result = UmulByInvert (a, o._v);
+
+ _v = negResult?_cairo_int128_negate(result):result;
+}
+cairo_uint128_t
+uint64x64_t::UmulByInvert (cairo_uint128_t a, cairo_uint128_t b)
+{
+ cairo_uint128_t result;
+ cairo_uint128_t hi, mid;
+ hi = _cairo_uint64x64_128_mul (a.hi, b.hi);
+ mid = _cairo_uint128_add (_cairo_uint64x64_128_mul (a.hi, b.lo),
+ _cairo_uint64x64_128_mul (a.lo, b.hi));
+ mid.lo = mid.hi;
+ mid.hi = 0;
+ result = _cairo_uint128_add (hi,mid);
+ return result;
+}
+uint64x64_t
+uint64x64_t::Invert (uint64_t v)
+{
+ NS_ASSERT (v > 1);
+ cairo_uint128_t a, factor;
+ a.hi = 1;
+ a.lo = 0;
+ factor.hi = 0;
+ factor.lo = v;
+ uint64x64_t result;
+ result._v = Udiv (a, factor);
+ uint64x64_t tmp = uint64x64_t (v, 0);
+ tmp.MulByInvert (result);
+ if (tmp.GetHigh () != 1)
+ {
+ cairo_uint128_t one = {1, 0};
+ result._v = _cairo_uint128_add (result._v, one);
+ }
+ return result;
+}
+
+
+} // namespace ns3
+
+// include directly to allow optimizations within the compilation unit.
+extern "C" {
+#include "cairo-wideint.c"
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/uint64x64-cairo.h Tue Aug 24 16:36:41 2010 +0200
@@ -0,0 +1,278 @@
+#ifndef UINT64X64_CAIRO_H
+#define UINT64X64_CAIRO_H
+
+#include <stdint.h>
+#include <math.h>
+#include "cairo-wideint-private.h"
+
+#ifdef __i386__
+#define UINT64x64_CAIRO_ASM 1
+#endif
+
+namespace ns3 {
+
+class uint64x64_t
+{
+public:
+ inline uint64x64_t ()
+ {
+ _v.hi = 0;
+ _v.lo = 0;
+ }
+ explicit inline uint64x64_t (double value)
+ {
+#define HPCAIRO_MAX_64 18446744073709551615.0
+ double fhi = floor (value);
+ int64_t hi = fhi;
+ uint64_t lo = (uint64_t) ((value - fhi) * HPCAIRO_MAX_64);
+ _v.hi = hi;
+ _v.lo = lo;
+#undef HPCAIRO_MAX_64
+ }
+ explicit inline uint64x64_t (int v)
+ {
+ _v.hi = v;
+ _v.lo = 0;
+ }
+ explicit inline uint64x64_t (long int v)
+ {
+ _v.hi = v;
+ _v.lo = 0;
+ }
+ explicit inline uint64x64_t (long long int v)
+ {
+ _v.hi = v;
+ _v.lo = 0;
+ }
+ explicit inline uint64x64_t (int64_t hi, uint64_t lo)
+ {
+ _v.hi = hi;
+ _v.lo = lo;
+ }
+
+ inline uint64x64_t (const uint64x64_t &o)
+ : _v (o._v) {}
+ inline uint64x64_t &operator = (const uint64x64_t &o)
+ {
+ _v = o._v;
+ return *this;
+ }
+
+ inline double GetDouble (void) const
+ {
+#define HPCAIRO_MAX_64 18446744073709551615.0
+ bool is_negative = IsNegative ();
+ cairo_int128_t value = is_negative ? _cairo_int128_negate (_v) : _v;
+ double flo = value.lo;
+ flo /= HPCAIRO_MAX_64;
+ double retval = value.hi;
+ retval += flo;
+ retval = is_negative ? -retval: retval;
+ return retval;
+#undef HPCAIRO_MAX_64
+ }
+ inline int64_t GetHigh (void) const
+ {
+ return (int64_t)_v.hi;
+ }
+ inline uint64_t GetLow (void) const
+ {
+ return _v.lo;
+ }
+
+ void MulByInvert (const uint64x64_t &o);
+
+ static uint64x64_t Invert (uint64_t v);
+
+private:
+ friend bool operator == (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator != (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator <= (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator >= (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator < (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator > (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator += (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator -= (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator *= (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator /= (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator + (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator - (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator * (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator / (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator + (const uint64x64_t &lhs);
+ friend uint64x64_t operator - (const uint64x64_t &lhs);
+ friend uint64x64_t operator ! (const uint64x64_t &lhs);
+ void Mul (const uint64x64_t &o);
+ void Div (const uint64x64_t &o);
+ static cairo_uint128_t Umul (cairo_uint128_t a, cairo_uint128_t b);
+ static cairo_uint128_t Udiv (cairo_uint128_t a, cairo_uint128_t b);
+ static cairo_uint128_t UmulByInvert (cairo_uint128_t a, cairo_uint128_t b);
+ inline bool IsNegative (void) const
+ {
+ int64_t hi = _v.hi;
+ return hi < 0;
+ }
+ inline void Negate (void)
+ {
+ _v.lo = ~_v.lo;
+ _v.hi = ~_v.hi;
+ if (++_v.lo == 0)
+ {
+ ++_v.hi;
+ }
+ }
+
+ cairo_int128_t _v;
+};
+
+#if defined(UINT64x64_CAIRO_ASM)
+#define xCMP_ls "jl"
+#define xCMP_le "jle"
+#define COMPARE(a,b,op) \
+ ({ \
+ int status; \
+ asm ("mov 0(%1),%%eax\n\t" \
+ "add 0(%2),%%eax\n\t" \
+ "mov 4(%1),%%eax\n\t" \
+ "adc 4(%2),%%eax\n\t" \
+ "mov 8(%1),%%eax\n\t" \
+ "adc 8(%2),%%eax\n\t" \
+ "mov 12(%1),%%eax\n\t" \
+ "adc 12(%2),%%eax\n\t" \
+ x##op " 1f\n\t" \
+ "mov $0,%0\n\t" \
+ "ja 2f\n" \
+ "1:\tmov $1,%0\n\t" \
+ "2:" \
+ : "=r" (status) \
+ : "r" (&a._v), "r" (&b._v) \
+ : "%eax", "cc"); \
+ bool retval = status == 1; \
+ retval; \
+ })
+#else
+#define xCMP_ls(a) (((int64_t)(a)._v.hi) < 0)
+#define xCMP_le(a) ((((int64_t)(a)._v.hi) < 0) || ((a)._v.hi == 0 && (a)._v.lo == 0))
+#define COMPARE(a,b,op) \
+ ({ \
+ uint64x64_t tmp = a; \
+ tmp -= b; \
+ bool result = x##op(tmp); \
+ result; \
+ })
+#endif
+
+inline bool operator == (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v.hi == rhs._v.hi && lhs._v.lo == lhs._v.lo;
+}
+
+inline bool operator != (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return ! (lhs == rhs);
+}
+
+inline bool operator < (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return COMPARE(lhs,rhs,CMP_ls);
+}
+inline bool operator <= (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return COMPARE(lhs,rhs,CMP_le);
+}
+
+inline bool operator >= (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return !(lhs < rhs);
+}
+inline bool operator > (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return !(lhs <= rhs);
+}
+inline uint64x64_t &operator += (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+#if UINT64x64_CAIRO_ASM
+ asm ("mov 0(%0),%%eax\n\t"
+ "add 0(%1),%%eax\n\t"
+ "mov %%eax,0(%0)\n\t"
+ "mov 4(%0),%%eax\n\t"
+ "adc 4(%1),%%eax\n\t"
+ "mov %%eax,4(%0)\n\t"
+ "mov 8(%0),%%eax\n\t"
+ "adc 8(%1),%%eax\n\t"
+ "mov %%eax,8(%0)\n\t"
+ "mov 12(%0),%%eax\n\t"
+ "adc 12(%1),%%eax\n\t"
+ "mov %%eax,12(%0)\n\t"
+ :
+ : "r" (&lhs._v), "r" (&rhs._v)
+ : "%eax", "cc");
+#else
+ lhs._v.hi += rhs._v.hi;
+ lhs._v.lo += rhs._v.lo;
+ if (lhs._v.lo < rhs._v.lo)
+ {
+ lhs._v.hi++;
+ }
+#endif
+ return lhs;
+}
+inline uint64x64_t &operator -= (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+#if UINT64x64_CAIRO_ASM
+ asm ("mov 0(%0),%%eax\n\t"
+ "sub 0(%1),%%eax\n\t"
+ "mov %%eax,0(%0)\n\t"
+ "mov 4(%0),%%eax\n\t"
+ "sbb 4(%1),%%eax\n\t"
+ "mov %%eax,4(%0)\n\t"
+ "mov 8(%0),%%eax\n\t"
+ "sbb 8(%1),%%eax\n\t"
+ "mov %%eax,8(%0)\n\t"
+ "mov 12(%0),%%eax\n\t"
+ "sbb 12(%1),%%eax\n\t"
+ "mov %%eax,12(%0)\n\t"
+ :
+ : "r" (&lhs._v), "r" (&rhs._v)
+ : "%eax", "cc");
+#else
+ lhs._v.hi -= rhs._v.hi;
+ lhs._v.lo -= rhs._v.lo;
+ if (lhs._v.lo > rhs._v.lo)
+ {
+ lhs._v.hi--;
+ }
+#endif
+ return lhs;
+}
+inline uint64x64_t &operator *= (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ lhs.Mul (rhs);
+ return lhs;
+}
+inline uint64x64_t &operator /= (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ lhs.Div (rhs);
+ return lhs;
+}
+
+inline uint64x64_t operator + (const uint64x64_t &lhs)
+{
+ return lhs;
+}
+
+inline uint64x64_t operator - (const uint64x64_t &lhs)
+{
+ uint64x64_t tmp = lhs;
+ tmp.Negate ();
+ return tmp;
+}
+
+inline uint64x64_t operator ! (const uint64x64_t &lhs)
+{
+ return (lhs._v.hi == 0 && lhs._v.lo == 0)?uint64x64_t (1, 0):uint64x64_t ();
+}
+
+} // namespace ns3
+
+#endif /* UINT64X64_CAIRO_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/uint64x64-double.h Tue Aug 24 16:36:41 2010 +0200
@@ -0,0 +1,153 @@
+#ifndef UINT64X64_DOUBLE_H
+#define UINT64X64_DOUBLE_H
+
+#include <iostream>
+#include <math.h>
+
+namespace ns3 {
+
+class uint64x64_t
+{
+public:
+ inline uint64x64_t ()
+ : _v (0) {}
+ explicit inline uint64x64_t (double v)
+ : _v (v) {}
+ explicit inline uint64x64_t (int v)
+ : _v (v) {}
+ explicit inline uint64x64_t (long int v)
+ : _v (v) {}
+ explicit inline uint64x64_t (long long int v)
+ : _v (v) {}
+ inline uint64x64_t (int64_t hi, uint64_t lo)
+ : _v (hi) {/* XXX */}
+
+ inline uint64x64_t (const uint64x64_t &o)
+ : _v (o._v) {}
+ inline uint64x64_t &operator = (const uint64x64_t &o)
+ {
+ _v = o._v;
+ return *this;
+ }
+
+ inline double GetDouble (void) const
+ {
+ return _v;
+ }
+ inline int64_t GetHigh (void) const
+ {
+ return (int64_t)floor (_v);
+ }
+ inline uint64_t GetLow (void) const
+ {
+ // XXX
+ return 0;
+ }
+
+ inline void MulByInvert (const uint64x64_t &o)
+ {
+ _v *= o._v;
+ }
+
+ static inline uint64x64_t Invert (uint64_t v)
+ {
+ double d = v;
+ return uint64x64_t (1/d);
+ }
+
+private:
+ friend bool operator == (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator != (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator <= (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator >= (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator < (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend bool operator > (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator += (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator -= (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator *= (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t &operator /= (uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator + (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator - (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator * (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator / (const uint64x64_t &lhs, const uint64x64_t &rhs);
+ friend uint64x64_t operator + (const uint64x64_t &lhs);
+ friend uint64x64_t operator - (const uint64x64_t &lhs);
+ friend uint64x64_t operator ! (const uint64x64_t &lhs);
+
+ double _v;
+};
+
+inline bool operator == (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v == rhs._v;
+}
+
+inline bool operator != (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v != rhs._v;
+}
+
+inline bool operator <= (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v <= rhs._v;
+}
+
+inline bool operator >= (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v >= rhs._v;
+}
+inline bool operator < (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v < rhs._v;
+}
+inline bool operator > (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ return lhs._v > rhs._v;
+}
+inline uint64x64_t &operator += (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ double tmp = lhs._v;
+ tmp += rhs._v;
+ lhs = uint64x64_t (tmp);
+ return lhs;
+}
+inline uint64x64_t &operator -= (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ double tmp = lhs._v;
+ tmp -= rhs._v;
+ lhs = uint64x64_t (tmp);
+ return lhs;
+}
+inline uint64x64_t &operator *= (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ double tmp = lhs._v;
+ tmp *= rhs._v;
+ lhs = uint64x64_t (tmp);
+ return lhs;
+}
+inline uint64x64_t &operator /= (uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ double tmp = lhs._v;
+ tmp /= rhs._v;
+ lhs = uint64x64_t (tmp);
+ return lhs;
+}
+
+inline uint64x64_t operator + (const uint64x64_t &lhs)
+{
+ return lhs;
+}
+
+inline uint64x64_t operator - (const uint64x64_t &lhs)
+{
+ return uint64x64_t (-lhs._v);
+}
+
+inline uint64x64_t operator ! (const uint64x64_t &lhs)
+{
+ return uint64x64_t (!lhs._v);
+}
+
+} // namespace ns3
+
+#endif /* UINT64X64_DOUBLE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/uint64x64.cc Tue Aug 24 16:36:41 2010 +0200
@@ -0,0 +1,460 @@
+#include "uint64x64.h"
+#include <stdint.h>
+#include <iostream>
+#include <sstream>
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+static uint8_t MostSignificantDigit (uint64_t value)
+{
+ uint8_t n = 0;
+ do
+ {
+ n++;
+ value /= 10;
+ } while (value != 0);
+ return n;
+}
+
+static uint64_t PowerOfTen (uint8_t n)
+{
+ uint64_t retval = 1;
+ while (n > 0)
+ {
+ retval *= 10;
+ n--;
+ }
+ return retval;
+}
+
+std::ostream &operator << (std::ostream &os, const uint64x64_t &value)
+{
+ int64_t hi = value.GetHigh ();
+ os << ((hi<0)?"-":"+") << ((hi<0)?-hi:hi) << ".";
+ uint64_t low = value.GetLow ();
+ uint8_t msd = MostSignificantDigit (~((uint64_t)0));
+ do
+ {
+ msd--;
+ uint64_t pow = PowerOfTen (msd);
+ uint8_t digit = low / pow;
+ NS_ASSERT (digit < 10);
+ os << (uint16_t) digit;
+ low -= digit * pow;
+ } while (msd > 0 && low > 0);
+ return os;
+}
+
+static uint64_t ReadDigits (std::string str)
+{
+ const char *buf = str.c_str ();
+ uint64_t retval = 0;
+ while (*buf != 0)
+ {
+ retval *= 10;
+ retval += *buf - 0x30;
+ buf++;
+ }
+ return retval;
+}
+
+std::istream &operator >> (std::istream &is, uint64x64_t &value)
+{
+ std::string str;
+
+ is >> str;
+ bool negative;
+ // skip heading spaces
+ std::string::size_type cur;
+ cur = str.find_first_not_of (" ");
+ std::string::size_type next;
+ // first, remove the sign.
+ next = str.find ("-", cur);
+ if (next != std::string::npos)
+ {
+ negative = true;
+ next++;
+ }
+ else
+ {
+ next = str.find ("+", cur);
+ if (next != std::string::npos)
+ {
+ next++;
+ }
+ else
+ {
+ next = cur;
+ }
+ negative = false;
+ }
+ cur = next;
+ int64_t hi;
+ uint64_t lo;
+ next = str.find(".", cur);
+ if (next != std::string::npos)
+ {
+ hi = ReadDigits (str.substr (cur, next-cur));
+ lo = ReadDigits (str.substr (next+1, str.size()-(next+1)));
+ }
+ else
+ {
+ hi = ReadDigits (str.substr (cur, str.size ()-cur));
+ lo = 0;
+ }
+ hi = negative?-hi:hi;
+ value = uint64x64_t (hi, lo);
+ return is;
+}
+
+} // namespace ns3
+
+#include "ns3/test.h"
+
+namespace ns3
+{
+
+class Uint64x64FracTestCase : public TestCase
+{
+public:
+ Uint64x64FracTestCase ();
+ virtual bool DoRun (void);
+ void CheckFrac (int64_t hi, uint64_t lo);
+};
+
+void
+Uint64x64FracTestCase::CheckFrac (int64_t hi, uint64_t lo)
+{
+ uint64x64_t tmp = uint64x64_t (hi,lo);
+ NS_TEST_EXPECT_MSG_EQ (tmp.GetHigh (), hi,
+ "High part does not match");
+ NS_TEST_EXPECT_MSG_EQ (tmp.GetLow (), lo,
+ "Low part does not match");
+}
+
+Uint64x64FracTestCase::Uint64x64FracTestCase ()
+ : TestCase ("Check that we can manipulate the high and low part of every number")
+{
+}
+bool
+Uint64x64FracTestCase::DoRun (void)
+{
+ CheckFrac (1, 0);
+ CheckFrac (1, 1);
+ CheckFrac (-1, 0);
+ CheckFrac (-1, 1);
+ return GetErrorStatus ();
+}
+
+
+class Uint64x64InputTestCase : public TestCase
+{
+public:
+ Uint64x64InputTestCase ();
+ virtual bool DoRun (void);
+ void CheckString (std::string str, int64_t hi, uint64_t lo);
+};
+Uint64x64InputTestCase::Uint64x64InputTestCase ()
+ : TestCase ("Check that we parse Uint64x64 numbers as strings")
+{
+}
+void
+Uint64x64InputTestCase::CheckString (std::string str, int64_t hi, uint64_t lo)
+{
+ std::istringstream iss;
+ iss.str (str);
+ uint64x64_t hp;
+ iss >> hp;
+ NS_TEST_EXPECT_MSG_EQ (hp.GetHigh (), hi, "High parts do not match for input string " << str);
+ NS_TEST_EXPECT_MSG_EQ (hp.GetLow (), lo, "Low parts do not match for input string " << str);
+}
+bool
+Uint64x64InputTestCase::DoRun (void)
+{
+ CheckString ("1", 1, 0);
+ CheckString ("+1", 1, 0);
+ CheckString ("-1", -1, 0);
+ CheckString ("1.0", 1, 0);
+ CheckString ("+1.0", 1, 0);
+ CheckString ("001.0", 1, 0);
+ CheckString ("+001.0", 1, 0);
+ CheckString ("020.0", 20, 0);
+ CheckString ("+020.0", 20, 0);
+ CheckString ("-1.0", -1, 0);
+ CheckString ("-1.0000", -1, 0);
+ CheckString ("1.0000000", 1, 0);
+ CheckString ("1.08446744073709551615", 1, 8446744073709551615LL);
+ CheckString ("-1.08446744073709551615", -1, 8446744073709551615LL);
+
+ return GetErrorStatus ();
+}
+
+class Uint64x64InputOutputTestCase : public TestCase
+{
+public:
+ Uint64x64InputOutputTestCase ();
+ virtual bool DoRun (void);
+ void CheckString (std::string str);
+};
+Uint64x64InputOutputTestCase::Uint64x64InputOutputTestCase ()
+ : TestCase ("Check that we can roundtrip Uint64x64 numbers as strings")
+{
+}
+void
+Uint64x64InputOutputTestCase::CheckString (std::string str)
+{
+ std::istringstream iss;
+ iss.str (str);
+ uint64x64_t value;
+ iss >> value;
+ std::ostringstream oss;
+ oss << value;
+ NS_TEST_EXPECT_MSG_EQ (oss.str (), str, "Converted string does not match expected string");
+}
+bool
+Uint64x64InputOutputTestCase::DoRun (void)
+{
+ CheckString ("+1.0");
+ CheckString ("-1.0");
+ CheckString ("+20.0");
+ CheckString ("+1.08446744073709551615");
+ CheckString ("-1.08446744073709551615");
+ CheckString ("+1.18446744073709551615");
+ CheckString ("-1.18446744073709551615");
+
+ return GetErrorStatus ();
+}
+
+#define CHECK_EXPECTED(a,b) \
+ NS_TEST_ASSERT_MSG_EQ ((a).GetHigh (),b,"Arithmetic failure: " << ((a).GetHigh ()) << "!=" << (b))
+
+#define V(v) \
+ uint64x64_t (v)
+
+class Uint64x64ArithmeticTestCase : public TestCase
+{
+public:
+ Uint64x64ArithmeticTestCase ();
+ virtual bool DoRun (void);
+};
+
+Uint64x64ArithmeticTestCase::Uint64x64ArithmeticTestCase ()
+ : TestCase ("Check basic arithmetic operations")
+{
+}
+bool
+Uint64x64ArithmeticTestCase::DoRun (void)
+{
+ uint64x64_t a, b;
+
+ CHECK_EXPECTED (V(1) - V(1), 0);
+ CHECK_EXPECTED (V(1) - V(2), -1);
+ CHECK_EXPECTED (V(1) - V(3), -2);
+ CHECK_EXPECTED (V(1) - V(-1), 2);
+ CHECK_EXPECTED (V(1) - V(-2), 3);
+ CHECK_EXPECTED (V(-3) - V(-4), 1);
+ CHECK_EXPECTED (V(-2) - V(3), -5);
+ CHECK_EXPECTED (V(1) + V(2), 3);
+ CHECK_EXPECTED (V(1) + V(-3), -2);
+ CHECK_EXPECTED (V(0) + V(0), 0);
+ CHECK_EXPECTED (V(0) * V(0), 0);
+ CHECK_EXPECTED (V(0) * V(1), 0);
+ CHECK_EXPECTED (V(0) * V(-1), 0);
+ CHECK_EXPECTED (V(1) * V(0), 0);
+ CHECK_EXPECTED (V(1) * V(1), 1);
+ CHECK_EXPECTED (V(1) * V(-1), -1);
+ CHECK_EXPECTED (V(-1) * V(-1), 1);
+ CHECK_EXPECTED (V(0) * V(1), 0);
+ CHECK_EXPECTED (V(0) * V(-1), 0);
+ CHECK_EXPECTED (V(-1) * V(1), -1);
+
+
+ CHECK_EXPECTED (V (2) * V(3) / V(3), 2);
+
+ // Below, the division loses precision because 2/3 is not
+ // representable exactly in 64.64 integers. So, we got
+ // something super close but the final rounding kills us.
+ CHECK_EXPECTED (V(2) / V(3) * V(3), 1);
+
+ // The example below shows that we really do not lose
+ // much precision internally: it is almost always the
+ // final conversion which loses precision.
+ CHECK_EXPECTED (V (2000000000) / V(3) * V(3), 1999999999);
+
+ return GetErrorStatus ();
+}
+
+class Uint64x64Bug455TestCase : public TestCase
+{
+public:
+ Uint64x64Bug455TestCase ();
+ virtual bool DoRun (void);
+};
+
+Uint64x64Bug455TestCase::Uint64x64Bug455TestCase ()
+ : TestCase ("Test case for bug 455")
+{
+}
+bool
+Uint64x64Bug455TestCase::DoRun (void)
+{
+ uint64x64_t a = uint64x64_t (0.1);
+ a /= uint64x64_t (1.25);
+ NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 0.08, "The original testcase");
+ a = uint64x64_t (0.5);
+ a *= uint64x64_t (5);
+ NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 2.5, "Simple test for multiplication");
+ a = uint64x64_t (-0.5);
+ a *= uint64x64_t (5);
+ NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -2.5, "Test sign, first operation negative");
+ a = uint64x64_t (-0.5);
+ a *=uint64x64_t (-5);
+ NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 2.5, "both operands negative");
+ a = uint64x64_t (0.5);
+ a *= uint64x64_t (-5);
+ NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -2.5, "only second operand negative");
+
+ return GetErrorStatus ();
+}
+
+class Uint64x64Bug863TestCase : public TestCase
+{
+public:
+ Uint64x64Bug863TestCase ();
+ virtual bool DoRun (void);
+};
+
+Uint64x64Bug863TestCase::Uint64x64Bug863TestCase ()
+ : TestCase ("Test case for bug 863")
+{
+}
+bool
+Uint64x64Bug863TestCase::DoRun (void)
+{
+ uint64x64_t a = uint64x64_t (0.9);
+ a /= uint64x64_t (1);
+ NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 0.9, "The original testcase");
+ a = uint64x64_t (0.5);
+ a /= uint64x64_t (0.5);
+ NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 1.0, "Simple test for division");
+ a = uint64x64_t (-0.5);
+ NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -0.5, "Check that we actually convert doubles correctly");
+ a /= uint64x64_t (0.5);
+ NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -1.0, "first argument negative");
+ a = uint64x64_t (0.5);
+ a /= uint64x64_t (-0.5);
+ NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -1.0, "second argument negative");
+ a = uint64x64_t (-0.5);
+ a /= uint64x64_t (-0.5);
+ NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 1.0, "both arguments negative");
+
+ return GetErrorStatus ();
+}
+
+class Uint64x64CompareTestCase : public TestCase
+{
+public:
+ Uint64x64CompareTestCase ();
+ virtual bool DoRun (void);
+};
+Uint64x64CompareTestCase::Uint64x64CompareTestCase ()
+ : TestCase ("Check basic compare operations")
+{
+}
+bool
+Uint64x64CompareTestCase::DoRun (void)
+{
+
+ NS_TEST_ASSERT_MSG_EQ ((V(-1) < V(1)), true, "a is smaller than b");
+ NS_TEST_ASSERT_MSG_EQ ((V(-1) > V(-2)), true, "a is bigger than b");
+ NS_TEST_ASSERT_MSG_EQ ((V(-1) == V(-1)), true, "a is equal to b");
+
+ NS_TEST_ASSERT_MSG_EQ ((V(1) > V(-1)), true, "a is bigger than b");
+ NS_TEST_ASSERT_MSG_EQ ((V(1) < V(2)), true, "a is smaller than b");
+
+ return GetErrorStatus ();
+}
+
+class Uint64x64InvertTestCase : public TestCase
+{
+public:
+ Uint64x64InvertTestCase ();
+ virtual bool DoRun (void);
+};
+
+Uint64x64InvertTestCase::Uint64x64InvertTestCase ()
+ : TestCase ("Test case for invertion")
+{
+}
+
+bool
+Uint64x64InvertTestCase::DoRun (void)
+{
+#define TEST(factor) \
+ do { \
+ uint64x64_t a; \
+ a = uint64x64_t::Invert (factor); \
+ uint64x64_t b = V (factor); \
+ b.MulByInvert (a); \
+ NS_TEST_ASSERT_MSG_EQ (b.GetHigh (), 1, \
+ "x * 1/x should be 1 for x=" << factor); \
+ uint64x64_t c = V (1); \
+ c.MulByInvert (a); \
+ NS_TEST_ASSERT_MSG_EQ (c.GetHigh (), 0, \
+ "1 * 1/x should be 0 for x=" << factor); \
+ uint64x64_t d = V (1); \
+ d /= (V(factor)); \
+ NS_TEST_ASSERT_MSG_EQ (d.GetDouble (), c.GetDouble (), \
+ "1 * 1/x should be equal to 1/x for x=" << factor); \
+ uint64x64_t e = V (-factor); \
+ e.MulByInvert (a); \
+ NS_TEST_ASSERT_MSG_EQ (e.GetHigh (), -1, \
+ "-x * 1/x should be -1 for x=" << factor); \
+ } while(false)
+ TEST(2);
+ TEST(3);
+ TEST(4);
+ TEST(5);
+ TEST(6);
+ TEST(10);
+ TEST(99);
+ TEST(100);
+ TEST(1000);
+ TEST(10000);
+ TEST(100000);
+ TEST(100000);
+ TEST(1000000);
+ TEST(10000000);
+ TEST(100000000);
+ TEST(1000000000);
+ TEST(10000000000LL);
+ TEST(100000000000LL);
+ TEST(1000000000000LL);
+ TEST(10000000000000LL);
+ TEST(100000000000000LL);
+ TEST(1000000000000000LL);
+#undef TEST
+ return GetErrorStatus ();
+}
+
+
+
+static class Uint64x64128TestSuite : public TestSuite
+{
+public:
+ Uint64x64128TestSuite ()
+ : TestSuite ("uint64x64", UNIT)
+ {
+ AddTestCase (new Uint64x64FracTestCase ());
+ AddTestCase (new Uint64x64InputTestCase ());
+ AddTestCase (new Uint64x64InputOutputTestCase ());
+ AddTestCase (new Uint64x64ArithmeticTestCase ());
+ AddTestCase (new Uint64x64Bug455TestCase ());
+ AddTestCase (new Uint64x64Bug863TestCase ());
+ AddTestCase (new Uint64x64CompareTestCase ());
+ AddTestCase (new Uint64x64InvertTestCase ());
+ }
+} g_uint64x64TestSuite;
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/uint64x64.h Tue Aug 24 16:36:41 2010 +0200
@@ -0,0 +1,51 @@
+#ifndef UINT64X64_H
+#define UINT64X64_H
+
+#include "ns3/simulator-config.h"
+
+#if defined (UINT64x64_USE_DOUBLE)
+#include "uint64x64-double.h"
+#elif defined (UINT64x64_USE_CAIRO)
+#include "uint64x64-cairo.h"
+#elif defined (UINT64x64_USE_128)
+#include "uint64x64-128.h"
+#endif
+
+#include <iostream>
+
+namespace ns3 {
+
+inline uint64x64_t operator + (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ uint64x64_t tmp = lhs;
+ tmp += rhs;
+ return tmp;
+}
+
+inline uint64x64_t operator - (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ uint64x64_t tmp = lhs;
+ tmp -= rhs;
+ return tmp;
+}
+
+inline uint64x64_t operator * (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ uint64x64_t tmp = lhs;
+ tmp *= rhs;
+ return tmp;
+}
+
+inline uint64x64_t operator / (const uint64x64_t &lhs, const uint64x64_t &rhs)
+{
+ uint64x64_t tmp = lhs;
+ tmp /= rhs;
+ return tmp;
+}
+
+std::ostream &operator << (std::ostream &os, const uint64x64_t &val);
+std::istream &operator << (std::istream &is, uint64x64_t &val);
+
+} // namespace ns3
+
+#endif /* UINT64X64_H */
--- a/src/simulator/wscript Mon Aug 23 19:01:11 2010 -0700
+++ b/src/simulator/wscript Tue Aug 24 16:36:41 2010 +0200
@@ -20,15 +20,15 @@
if Options.options.high_precision_as_double:
- conf.define('USE_HIGH_PRECISION_DOUBLE', 1)
+ conf.define('UINT64x64_USE_DOUBLE', 1)
conf.env['USE_HIGH_PRECISION_DOUBLE'] = 1
highprec = 'long double'
elif a or b:
- conf.define('USE_HIGH_PRECISION_128', 1)
+ conf.define('UINT64x64_USE_128', 1)
conf.env['USE_HIGH_PRECISION_128'] = 1
highprec = '128-bit integer'
else:
- conf.define('USE_HIGH_PRECISION_CAIRO', 1)
+ conf.define('UINT64x64_USE_CAIRO', 1)
conf.env['USE_HIGH_PRECISION_CAIRO'] = 1
highprec = 'cairo 128-bit integer'
@@ -54,8 +54,7 @@
def build(bld):
sim = bld.create_ns3_module('simulator', ['core'])
sim.source = [
- 'high-precision.cc',
- 'time-base.cc',
+ 'uint64x64.cc',
'time.cc',
'event-id.cc',
'scheduler.cc',
@@ -77,8 +76,7 @@
headers = bld.new_task_gen('ns3header')
headers.module = 'simulator'
headers.source = [
- 'high-precision.h',
- 'time-base.h',
+ 'uint64x64.h',
'nstime.h',
'event-id.h',
'event-impl.h',
@@ -101,17 +99,16 @@
env = bld.env_of_name('default')
if env['USE_HIGH_PRECISION_DOUBLE']:
- headers.source.extend(['high-precision-double.h'])
+ headers.source.extend(['uint64x64-double.h'])
elif env['USE_HIGH_PRECISION_128']:
- headers.source.extend(['high-precision-128.h'])
- sim.source.extend(['high-precision-128.cc'])
+ headers.source.extend(['uint64x64-128.h'])
+ sim.source.extend(['uint64x64-128.cc'])
elif env['USE_HIGH_PRECISION_CAIRO']:
sim.source.extend([
- 'high-precision-cairo.cc',
-# 'cairo-wideint.c',
+ 'uint64x64-cairo.cc',
])
headers.source.extend([
- 'high-precision-cairo.h',
+ 'uint64x64-cairo.h',
'cairo-wideint-private.h',
])