merge with bug826 fixes
authorMathieu Lacage <mathieu.lacage@sophia.inria.fr>
Sat, 07 Aug 2010 14:30:18 +0200
changeset 6519 ba4b2956bd42
parent 6491 d9d460a6367f (current diff)
parent 6518 687b051c3039 (diff)
child 6520 e9a49c7cef26
merge with bug826 fixes
src/simulator/high-precision-cairo.h
src/simulator/simulator-impl.h
--- a/src/common/data-rate.h	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/common/data-rate.h	Sat Aug 07 14:30:18 2010 +0200
@@ -125,8 +125,8 @@
  * \param rhs
  * \return Bits transmitted in rhs seconds at lhs b/s
  */
-double operator*(const DataRate& lhs, const TimeUnit<1>& rhs);
-double operator*(const TimeUnit<1>& lhs, const DataRate& rhs);
+double operator*(const DataRate& lhs, const Time& rhs);
+double operator*(const Time& lhs, const DataRate& rhs);
 
 } //namespace ns3
 
--- a/src/devices/csma/backoff.cc	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/devices/csma/backoff.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -67,7 +67,7 @@
 
   uint32_t backoffSlots = (uint32_t)m_rng.GetValue(minSlot, maxSlot);
 
-  backoff = Scalar(backoffSlots) * m_slotTime;
+  backoff = Scalar (backoffSlots) * m_slotTime;
   return (backoff);
 }
 
--- a/src/internet-stack/ndisc-cache.cc	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/internet-stack/ndisc-cache.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -157,7 +157,7 @@
   m_retransTimer(Timer::CANCEL_ON_DESTROY),
   m_probeTimer(Timer::CANCEL_ON_DESTROY),
   m_delayTimer(Timer::CANCEL_ON_DESTROY),
-  m_lastReachabilityConfirmation(Timer::CANCEL_ON_DESTROY),
+  m_lastReachabilityConfirmation(Seconds (0.0)),
   m_nsRetransmit (0)
 {
   NS_LOG_FUNCTION_NOARGS ();
--- a/src/mobility/waypoint.cc	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/mobility/waypoint.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -28,8 +28,8 @@
   position (waypointPosition)
 {}
 Waypoint::Waypoint ()
-  : time (0.0),
-  position (0,0,0)
+  : time (Seconds (0.0)),
+    position (0,0,0)
 {}
 
 std::ostream &operator << (std::ostream &os, const Waypoint &waypoint)
--- a/src/simulator/default-simulator-impl.cc	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/default-simulator-impl.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -40,7 +40,7 @@
 DefaultSimulatorImpl::GetTypeId (void)
 {
   static TypeId tid = TypeId ("ns3::DefaultSimulatorImpl")
-    .SetParent<Object> ()
+    .SetParent<SimulatorImpl> ()
     .AddConstructor<DefaultSimulatorImpl> ()
     ;
   return tid;
--- a/src/simulator/high-precision-128.cc	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/high-precision-128.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -1,30 +1,59 @@
 #include "high-precision-128.h"
-#include "ns3/fatal-error.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)
 void
 HighPrecision::Mul (HighPrecision const &o)
 {
-  bool negResult, negA, negB;
-    // take the sign of the operands
-  negA = m_value < 0;
-  negB = o.m_value < 0;
-  // the result is negative only if one of the operand is negative
-  negResult = (negA && !negB) || (!negA && negB);
-  // now take the absolute part to make sure that the resulting operands are positive
+  bool negResult;
   uint128_t a, b;
-  a = negA?-m_value:m_value;
-  b = negB?-o.m_value:o.m_value;
+  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;
 
@@ -42,28 +71,25 @@
   // 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
-  if ((hiPart & MASK_HI) != 0)
-    {
-      NS_FATAL_ERROR ("High precision 128 bits multiplication error: multiplication overflow.");
-    }
-  // add the sign to the result
-  result = negResult ? -result:result;
-  m_value = result;
+  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, negA, negB;
-    // take the sign of the operands
-  negA = m_value < 0;
-  negB = o.m_value < 0;
-  // the result is negative only if one of the operand is negative
-  negResult = (negA && !negB) || (!negA && negB);
-  // now take the absolute part to make sure that the resulting operands are positive
+  bool negResult;
   uint128_t a, b;
-  a = negA?-m_value:m_value;
-  b = negB?-o.m_value:o.m_value;
+  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;
@@ -82,8 +108,50 @@
     }
   quo = rem / div;
   result = result + quo;
-  result = negResult ? -result:result;
-  m_value = result;
+  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;
 }
 
 } // namespace ns3
--- a/src/simulator/high-precision-128.h	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/high-precision-128.h	Sat Aug 07 14:30:18 2010 +0200
@@ -24,19 +24,37 @@
 #include <math.h>
 #include <stdint.h>
 
+#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 ();
-  inline HighPrecision (int64_t value, bool dummy);
-  inline HighPrecision (double value);
+  explicit inline HighPrecision (int64_t value, bool dummy);
+  explicit inline HighPrecision (double value);
 
   inline int64_t GetInteger (void) const;
   inline double GetDouble (void) const;
@@ -44,11 +62,28 @@
   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);
 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
 };
 
 } // namespace ns3
@@ -75,17 +110,20 @@
 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;
 }
 
--- a/src/simulator/high-precision-cairo.cc	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/high-precision-cairo.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -19,17 +19,31 @@
  */
 #include "high-precision-cairo.h"
 #include "ns3/test.h"
-#include "ns3/fatal-error.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)
 {
-  // use the 128 bits multiplication
-  m_value = Mul128 (m_value,o.m_value);
+  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;
 }
 
 
@@ -39,22 +53,9 @@
  * as the fractional part. It takes into account the sign
  * of the operands to produce a signed 128 bits result.
  */
-cairo_int128_t
-HighPrecision::Mul128 (cairo_int128_t sa, cairo_int128_t sb ) const
+cairo_uint128_t
+HighPrecision::Umul (cairo_uint128_t a, cairo_uint128_t b)
 {
-  bool negResult, negA, negB;
-
-  negA = _cairo_int128_negative (sa);
-  negB = _cairo_int128_negative (sb);
-  // the result is negative only if one of the operand is negative
-  negResult = (negA && !negB) || (!negA && negB);
-  // now take the absolute part to make sure that the resulting operands are positive
-  cairo_uint128_t a, b;
-  a = _cairo_int128_to_uint128 (sa);
-  b = _cairo_int128_to_uint128 (sb);
-  a = negA ? _cairo_uint128_negate (a) : a;
-  b = negB ? _cairo_uint128_negate (b) : b;
-
   cairo_uint128_t result;
   cairo_uint128_t hiPart,loPart,midPart;
 
@@ -73,38 +74,23 @@
   // 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
-  if (hiPart.hi != 0)
-    {
-      NS_FATAL_ERROR ("High precision 128 bits multiplication error: multiplication overflow.");
-    }
-  // add the sign to the result
-  result = negResult ? _cairo_uint128_negate (result) : result;
-  return _cairo_uint128_to_int128 (result);
+  NS_ABORT_MSG_IF (hiPart.hi != 0,
+                   "High precision 128 bits multiplication error: multiplication overflow.");
+  return result;
 }
 
 void
 HighPrecision::Div (HighPrecision const &o)
 {
-  cairo_int128_t result = Div128 (m_value, o.m_value);
-  m_value = result;
+  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_int128_t
-HighPrecision::Div128 (cairo_int128_t sa, cairo_int128_t sb) const
+cairo_uint128_t
+HighPrecision::Udiv (cairo_uint128_t a, cairo_uint128_t b)
 {
-  bool negResult, negA, negB;
-  // take the sign of the operands
-  negA = _cairo_int128_negative (sa);
-  negB = _cairo_int128_negative (sb);
-  // the result is negative only if one of the operand is negative
-  negResult = (negA && !negB) || (!negA && negB);
-  // now take the absolute part to make sure that the resulting operands are positive
-  cairo_uint128_t a, b;
-  a = _cairo_int128_to_uint128 (sa);
-  b = _cairo_int128_to_uint128 (sb);
-  a = negA ? _cairo_uint128_negate (a) : a;
-  b = negB ? _cairo_uint128_negate (b) : b;
-
   cairo_uquorem128_t qr = _cairo_uint128_divrem (a, b);
   cairo_uint128_t result = _cairo_uint128_lsl (qr.quo, 64);
   // Now, manage the remainder
@@ -123,9 +109,56 @@
     }
   qr = _cairo_uint128_divrem (rem, div);
   result = _cairo_uint128_add (result, qr.quo);
-  result = negResult ? _cairo_uint128_negate (result) : result;
-  return _cairo_uint128_to_int128 (result);
+  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;
+}
+
 
 } // namespace ns3
 
+// include directly to allow optimizations within the compilation unit.
+extern "C" {
+#include "cairo-wideint.c"
+}
--- a/src/simulator/high-precision-cairo.h	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/high-precision-cairo.h	Sat Aug 07 14:30:18 2010 +0200
@@ -37,37 +37,6 @@
  * Division operations (there are really really super costly)
  * and Comparison operations (because there are typically a lot of
  * these in any complex timekeeping code).
- *
- * So, the code tries really hard to perform any of these 128 bit
- * operations by doing all arithmetic on 64 bit integers when possible
- * (i.e., when there is no fractional part. This is a very common case).
- * Hence, the following code has a m_fastValue (64 bits) and a
- * m_slowValue (128 bits). m_fastValue is used by default and the code
- * converts it to a m_slowValue when needed.
- *
- * If you want to monitor the efficiency of this strategy, you can
- * enable the macro HP128INC below and call the HighPrecision::PrintStats
- * method at the end of the simulation.
- *
- * Explanation of Slow and Fast values:
- *
- * HighPrecision class create a fastValue and a slowValue depending on the
- * input number. If the input is an integer with 0 fractional part, it will
- * use the fastValue which will contain the integer in a 64 bits format. If
- * it has a fractional part, the slowValue will be used. It is represented
- * simply as a high part slowValue.hi which will contain the integer part
- * and the fractional part slowValue.lo which will contain the factional
- * part as an integer (obtained by multiplying the fractional part by 2^64).
- *
- * Explanation of Slow and Fast operations:
- *
- * If both operands are fastValues, we will perform fast operations, i-e
- * simply using integer operations. If we have though one of the value is
- * slowValue we need to convert the fastValue into a slow one. It is simply
- * obtained by putting the slowValue.lo = 0 and slowValue.hi = fastValue.
- * After that we apply the slow operation which will be a 128 bits operation
- * with two 128 bits operands.
- *
  */
 
 namespace ns3 {
@@ -76,8 +45,8 @@
 {
 public:
   inline HighPrecision ();
-  inline HighPrecision (int64_t value, bool dummy);
-  inline HighPrecision (double value);
+  explicit inline HighPrecision (int64_t value, bool dummy);
+  explicit inline HighPrecision (double value);
 
   inline int64_t GetInteger (void) const;
   inline double GetDouble (void) const;
@@ -85,12 +54,15 @@
   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);
 private:
-  cairo_uint128_t  Mul128 (cairo_uint128_t, cairo_uint128_t ) const;
-  cairo_int128_t Div128 (cairo_int128_t sa, cairo_int128_t sb) const;
+  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;
--- a/src/simulator/high-precision-double.h	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/high-precision-double.h	Sat Aug 07 14:30:18 2010 +0200
@@ -35,8 +35,8 @@
 {
 public:
   inline HighPrecision ();
-  inline HighPrecision (int64_t value, bool dummy);
-  inline HighPrecision (double value);
+  explicit inline HighPrecision (int64_t value, bool dummy);
+  explicit inline HighPrecision (double value);
 
   inline int64_t GetInteger (void) const;
   inline double GetDouble (void) const;
@@ -44,6 +44,8 @@
   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);
@@ -101,10 +103,21 @@
 {
   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;
+  return (m_value < o.m_value)?-1:(m_value == o.m_value)?0:1;
 }
 HighPrecision
 HighPrecision::Zero (void)
--- a/src/simulator/high-precision.cc	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/high-precision.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -282,6 +282,70 @@
   return false;
 }
 
+class Hp128InvertTestCase : public TestCase
+{
+public:
+  Hp128InvertTestCase ();
+  virtual bool DoRun (void);
+};
+
+Hp128InvertTestCase::Hp128InvertTestCase ()
+  : TestCase ("Test case for invertion")
+{
+}
+
+bool
+Hp128InvertTestCase::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 false;
+}
+
+
 static class HighPrecision128TestSuite : public TestSuite
 {
 public:
@@ -292,6 +356,7 @@
     AddTestCase (new Hp128Bug455TestCase ());
     AddTestCase (new Hp128Bug863TestCase ());
     AddTestCase (new Hp128CompareTestCase ());
+    AddTestCase (new Hp128InvertTestCase ());
   }
 } g_highPrecision128TestSuite;
 
--- a/src/simulator/nstime.h	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/nstime.h	Sat Aug 07 14:30:18 2010 +0200
@@ -30,34 +30,6 @@
 
 namespace ns3 {
 
-namespace TimeStepPrecision {
-
-enum precision_t
-{
-  S  = 0,
-  MS = 3,
-  US = 6,
-  NS = 9,
-  PS = 12,
-  FS = 15
-};
-/**
- * \param precision the new precision to use
- *
- * This should be invoked before any Time object
- * is created. i.e., it should be invoked at the very start
- * of every simulation. The unit specified by this method
- * is used as the unit of the internal simulation time
- * which is stored as a 64 bit integer.
- */
-void Set (precision_t precision);
-/**
- * \returns the currently-used time precision.
- */
-precision_t Get (void);
-
-} // namespace TimeStepPrecision
-
 
 /**
  * \ingroup simulator
@@ -109,251 +81,107 @@
  *  - \ref ns3-Time-Max ns3::Max
  *  - \ref ns3-Time-Min ns3::Min
  */
-template <int N>
-class TimeUnit
+/**
+ * \ingroup time
+ * \brief keep track of time values and allow control of global simulation resolution
+ *
+ * This class defines all the classic C++ arithmetic
+ * operators +, -, *, /, and all the classic comparison operators:
+ * ==, !=, <, >, <=, >=. It is thus easy to add, substract, or
+ * multiply multiple Time objects.
+ *
+ * The ns3::Scalar, ns3::TimeSquare, and ns3::TimeInvert classes
+ * are backward-compatibility aliases for ns3::Time.
+ *
+ * For example:
+ * \code
+ * Time t1 = Seconds (10.0);
+ * Time t2 = Seconds (10.0);
+ * Time t3 = t1 * t2;
+ * Time t4 = t1 / t2;
+ * Time t5 = t3 * t1;
+ * Time t6 = t1 / t5;
+ * Time t7 = t3;
+ * \endcode
+ *
+ * You can also use the following non-member functions to manipulate
+ * any of these ns3::Time object:
+ *  - \ref ns3-Time-Abs ns3::Abs
+ *  - \ref ns3-Time-Max ns3::Max
+ *  - \ref ns3-Time-Min ns3::Min
+ *
+ * This class also controls
+ * the resolution of the underlying time value . The default resolution
+ * is nanoseconds. That is, TimeStep (1).GetNanoSeconds () will return
+ * 1. It is possible to either increase or decrease the resolution and the
+ * code tries really hard to make this easy.
+ *
+ * If your resolution is X (say, nanoseconds) and if you create Time objects 
+ * with a lower resolution (say, picoseconds), don't expect that this 
+ * code will return 1: PicoSeconds (1).GetPicoSeconds (). It will most 
+ * likely return 0 because the Time object has only 64 bits of fractional 
+ * precision which means that PicoSeconds (1) is stored as a 64-bit aproximation
+ * of 1/1000 in the Time object. If you later multiply it again by the exact 
+ * value 1000, the result is unlikely to be 1 exactly. It will be close to
+ * 1 but not exactly 1.
+ * 
+ * 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
+ * to switch the global resolution to picoseconds to avoid nasty surprises.
+ *
+ * Another important issue to keep in mind is that if you increase the
+ * global resolution, you also implicitely decrease the range of your simulation.
+ * i.e., the global simulation time is stored in a 64 bit integer whose interpretation
+ * will depend on the global resolution so, 2^64 picoseconds which is the maximum
+ * duration of your simulation if the global resolution is picoseconds 
+ * is smaller than 2^64 nanoseconds which is the maximum duration of your simulation
+ * if the global resolution is nanoseconds.
+ *
+ * Finally, don't even think about ever changing the global resolution after
+ * creating Time objects: all Time objects created before the call to SetResolution
+ * will contain values which are not updated to the new resolution. In practice,
+ * the default value for the attributes of many models is indeed calculated
+ * before the main function of the main program enters. Because of this, if you
+ * use one of these models (and it's likely), it's going to be hard to change
+ * the global simulation resolution in a way which gives reasonable results. This
+ * issue has been filed as bug 954 in the ns-3 bugzilla installation.
+ */
+class Time
 {
 public:
-  TimeUnit ();
-  TimeUnit (TimeUnit const &o);
-  TimeUnit operator = (TimeUnit const &o);
-  TimeUnit (HighPrecision data);
-
   /**
-   * \return true if the time is zero, false otherwise.
-   */
-  bool IsZero (void) const;
-  /**
-   * \return true if the time is negative or zero, false otherwise.
+   * The unit to use to interpret a number representing time
    */
-  bool IsNegative (void) const;
-  /**
-   * \return true if the time is positive or zero, false otherwise.
-   */
-  bool IsPositive (void) const;
-  /**
-   * \return true if the time is strictly negative, false otherwise.
-   */
-  bool IsStrictlyNegative (void) const;
-  /**
-   * \return true if the time is strictly positive, false otherwise.
-   */
-  bool IsStrictlyPositive (void) const;
+  enum Unit
+    {
+      S  = 0,
+      MS = 1,
+      US = 2,
+      NS = 3,
+      PS = 4,
+      FS = 5,
+      LAST = 6
+    };
+
+  inline Time &operator = (const Time &o)
+  {
+    m_data = o.m_data;
+    return *this;
+  }
+  inline Time ()
+    : m_data ()
+  {}
+  inline Time(const Time &o)
+    : m_data (o.m_data)
+  {}
+  explicit inline Time (const HighPrecision &data)
+    : m_data (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 Time<N> type.
-   */
-  HighPrecision const &GetHighPrecision (void) const;
-  HighPrecision * PeekHighPrecision (void);
-
-private:
-  HighPrecision m_data;
-};
-
-template <int N>
-TimeUnit<N>::TimeUnit ()
-  : m_data ()
-{
-}
-template <int N>
-TimeUnit<N>::TimeUnit (TimeUnit const &o)
-  : m_data (o.m_data)
-{
-}
-template <int N>
-TimeUnit<N>
-TimeUnit<N>::operator = (TimeUnit const &o)
-{
-  m_data = o.m_data;
-  return *this;
-}
-template <int N>
-TimeUnit<N>::TimeUnit (HighPrecision data)
-  : m_data (data)
-{
-}
-
-template <int N>
-HighPrecision const &
-TimeUnit<N>::GetHighPrecision (void) const
-{
-  return m_data;
-}
-template <int N>
-HighPrecision *
-TimeUnit<N>::PeekHighPrecision (void)
-{
-  return &m_data;
-}
-template <int N>
-bool
-TimeUnit<N>::IsZero (void) const
-{
-  return m_data.Compare (HighPrecision::Zero ()) == 0;
-}
-template <int N>
-bool
-TimeUnit<N>::IsNegative (void) const
-{
-  return m_data.Compare (HighPrecision::Zero ()) <= 0;
-}
-template <int N>
-bool
-TimeUnit<N>::IsPositive (void) const
-{
-  return m_data.Compare (HighPrecision::Zero ()) >= 0;
-}
-template <int N>
-bool
-TimeUnit<N>::IsStrictlyNegative (void) const
-{
-  return m_data.Compare (HighPrecision::Zero ()) < 0;
-}
-template <int N>
-bool
-TimeUnit<N>::IsStrictlyPositive (void) const
-{
-  return m_data.Compare (HighPrecision::Zero ()) > 0;
-}
-
-template <int N>
-bool
-operator == (TimeUnit<N> const &lhs, TimeUnit<N> const &rhs)
-{
-  return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) == 0;
-}
-template <int N>
-bool
-operator != (TimeUnit<N> const &lhs, TimeUnit<N> const &rhs)
-{
-  return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) != 0;
-}
-template <int N>
-bool
-operator <= (TimeUnit<N> const &lhs, TimeUnit<N> const &rhs)
-{
-  return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) <= 0;
-}
-template <int N>
-bool
-operator >= (TimeUnit<N> const &lhs, TimeUnit<N> const &rhs)
-{
-  return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) >= 0;
-}
-template <int N>
-bool
-operator < (TimeUnit<N> const &lhs, TimeUnit<N> const &rhs)
-{
-  return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) < 0;
-}
-template <int N>
-bool
-operator > (TimeUnit<N> const &lhs, TimeUnit<N> const &rhs)
-{
-  return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) > 0;
-}
-template <int N>
-TimeUnit<N> operator + (TimeUnit<N> const &lhs, TimeUnit<N> const &rhs)
-{
-  HighPrecision retval = lhs.GetHighPrecision ();
-  retval.Add (rhs.GetHighPrecision ());
-  return TimeUnit<N> (retval);
-}
-template <int N>
-TimeUnit<N> operator - (TimeUnit<N> const &lhs, TimeUnit<N> const &rhs)
-{
-  HighPrecision retval = lhs.GetHighPrecision ();
-  retval.Sub (rhs.GetHighPrecision ());
-  return TimeUnit<N> (retval);
-}
-template <int N1, int N2>
-TimeUnit<N1 + N2> operator * (TimeUnit<N1> const &lhs, TimeUnit<N2> const &rhs)
-{
-  HighPrecision retval = lhs.GetHighPrecision ();
-  retval.Mul (rhs.GetHighPrecision ());
-  return TimeUnit<N1 + N2> (retval);
-}
-template <int N1, int N2>
-TimeUnit<N1 - N2> operator / (TimeUnit<N1> const &lhs, TimeUnit<N2> const &rhs)
-{
-  NS_ASSERT (rhs.GetHighPrecision ().GetDouble () != 0);
-  HighPrecision retval = lhs.GetHighPrecision ();
-  retval.Div (rhs.GetHighPrecision ());
-  return TimeUnit<N1 - N2> (retval);
-}
-template <int N>
-TimeUnit<N> &operator += (TimeUnit<N> &lhs, TimeUnit<N> const &rhs)
-{
-  HighPrecision *lhsv = lhs.PeekHighPrecision ();
-  lhsv->Add (rhs.GetHighPrecision ());
-  return lhs;
-}
-template <int N>
-TimeUnit<N> &operator -= (TimeUnit<N> &lhs, TimeUnit<N> const &rhs)
-{
-  HighPrecision *lhsv = lhs.PeekHighPrecision ();
-  lhsv->Sub (rhs.GetHighPrecision ());
-  return lhs;
-}
-
-
-/**
- * \anchor ns3-Time-Abs
- * \relates ns3::TimeUnit
- * \param time the input value
- * \returns the absolute value of the input value.
- */
-template <int N>
-TimeUnit<N> Abs (TimeUnit<N> const &time)
-{
-  return TimeUnit<N> (Abs (time.GetHighPrecision ()));
-}
-/**
- * \anchor ns3-Time-Max
- * \relates ns3::TimeUnit
- * \param ta the first value
- * \param tb the seconds value
- * \returns the max of the two input values.
- */
-template <int N>
-TimeUnit<N> Max (TimeUnit<N> const &ta, TimeUnit<N> const &tb)
-{
-  HighPrecision a = ta.GetHighPrecision ();
-  HighPrecision b = tb.GetHighPrecision ();
-  return TimeUnit<N> (Max (a, b));
-}
-/**
- * \anchor ns3-Time-Min
- * \relates ns3::TimeUnit
- * \param ta the first value
- * \param tb the seconds value
- * \returns the min of the two input values.
- */
-template <int N>
-TimeUnit<N> Min (TimeUnit<N> const &ta, TimeUnit<N> const &tb)
-{
-  HighPrecision a = ta.GetHighPrecision ();
-  HighPrecision b = tb.GetHighPrecision ();
-  return TimeUnit<N> (Min (a, b));
-}
-
-// Explicit instantiation of the TimeUnit template for N=1, with a few
-// additional methods that should not be available for N!=1
-// \class TimeUnit<1>
-
-class TimeValue;
-
-template <>
-class TimeUnit<1>
-{
-  // -*- New methods -*-
-public:
-  /**
    * \brief String constructor
-   * Construct TimeUnit<1> object from common time expressions like "
+   * Construct Time object from common time expressions like "
    * 1ms" or "10s".  Supported units include:
    * - s  (seconds)
    * - ms (milliseconds)
@@ -365,177 +193,378 @@
    * There can be no white space between the numerical portion
    * and the units.  Any otherwise malformed string causes a fatal error to
    * occur.
-   * \param s The string to parse into a TimeUnit<1>
+   * \param s The string to parse into a Time
+   */
+  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 true if the time is negative or zero, false otherwise.
+   */
+  inline bool IsNegative (void) const
+  {
+    return m_data.Compare (HighPrecision::Zero ()) <= 0;
+  }
+  /**
+   * \return true if the time is positive or zero, false otherwise.
+   */
+  inline bool IsPositive (void) const
+  {
+    return m_data.Compare (HighPrecision::Zero ()) >= 0;
+  }
+  /**
+   * \return true if the time is strictly negative, false otherwise.
    */
-  TimeUnit<1> (const std::string & s);
+  inline bool IsStrictlyNegative (void) const
+  {
+    return m_data.Compare (HighPrecision::Zero ()) < 0;
+  }
+  /**
+   * \return true if the time is strictly positive, false otherwise.
+   */
+  inline bool IsStrictlyPositive (void) const
+  {
+    return m_data.Compare (HighPrecision::Zero ()) > 0;
+  }
+
+  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;
+  }
+
   /**
    * \returns an approximation in seconds of the time stored in this
    *          instance.
    */
-  double GetSeconds (void) const;
+  inline double GetSeconds (void) const
+  {
+    return ToDouble (*this, Time::S);
+  }
 
   /**
    * \returns an approximation in milliseconds of the time stored in this
    *          instance.
    */
-  int64_t GetMilliSeconds (void) const;
+  inline int64_t GetMilliSeconds (void) const
+  {
+    return ToInteger (*this, Time::MS);
+  }
   /**
    * \returns an approximation in microseconds of the time stored in this
    *          instance.
    */
-  int64_t GetMicroSeconds (void) const;
+  inline int64_t GetMicroSeconds (void) const
+  {
+    return ToInteger (*this, Time::US);
+  }
   /**
    * \returns an approximation in nanoseconds of the time stored in this
    *          instance.
    */
-  int64_t GetNanoSeconds (void) const;
+  inline int64_t GetNanoSeconds (void) const
+  {
+    return ToInteger (*this, Time::NS);
+  }
   /**
    * \returns an approximation in picoseconds of the time stored in this
    *          instance.
    */
-  int64_t GetPicoSeconds (void) const;
+  inline int64_t GetPicoSeconds (void) const
+  {
+    return ToInteger (*this, Time::PS);
+  }
   /**
    * \returns an approximation in femtoseconds of the time stored in this
    *          instance.
    */
-  int64_t GetFemtoSeconds (void) const;
+  inline int64_t GetFemtoSeconds (void) const
+  {
+    return ToInteger (*this, Time::FS);
+  }
   /**
    * \returns an approximation of the time stored in this
    *          instance in the units specified in m_tsPrecision.
    */
-  int64_t GetTimeStep (void) const;
-
-  // -*- The rest is the the same as in the generic template class -*-
-public:
-  TimeUnit ()
-    : m_data ()
-  {
-  }
-  TimeUnit (TimeUnit const &o)
-    : m_data (o.m_data)
+  inline int64_t GetTimeStep (void) const
   {
-  }
-  TimeUnit operator = (TimeUnit const &o)
-  {
-    m_data = o.m_data;
-    return *this;
+    int64_t timeValue = m_data.GetInteger ();
+    return timeValue;
   }
-  TimeUnit (HighPrecision data)
-    : m_data (data)
-  {
-  }
-  bool IsZero (void) const
+
+
+  /**
+   * \param resolution the new resolution to use
+   *
+   * Change the global resolution used to convert all 
+   * user-provided time values in Time objects and Time objects
+   * in user-expected time units.
+   */
+  static void SetResolution (enum Unit resolution);
+  /**
+   * \returns the current global resolution.
+   */
+  static enum Unit GetResolution (void);
+  /**
+   * \param value to convert into a Time object
+   * \param timeUnit the unit of the value to convert
+   * \return a new Time object
+   *
+   * This method interprets the input value according to the input
+   * unit and constructs a matching Time object.
+   *
+   * \sa FromDouble, ToDouble, ToInteger
+   */
+  inline static Time FromInteger (uint64_t value, enum Unit timeUnit)
   {
-    return m_data.Compare (HighPrecision::Zero ()) == 0;
-  }
-  bool IsNegative (void) const
-  {
-    return m_data.Compare (HighPrecision::Zero ()) <= 0;
+    struct Information *info = PeekInformation (timeUnit);
+    if (info->fromMul)
+      {
+        value *= info->factor;
+        return Time (HighPrecision (value, false));
+      }
+    return From (HighPrecision (value, false), timeUnit);
   }
-  bool IsPositive (void) const
-  {
-    return m_data.Compare (HighPrecision::Zero ()) >= 0;
-  }
-  bool IsStrictlyNegative (void) const
+  /**
+   * \param value to convert into a Time object
+   * \param timeUnit the unit of the value to convert
+   * \return a new Time object
+   *
+   * \sa FromInteger, ToInteger, ToDouble
+   */
+  inline static Time FromDouble (double value, enum Unit timeUnit)
   {
-    return m_data.Compare (HighPrecision::Zero ()) < 0;
-  }
-  bool IsStrictlyPositive (void) const
-  {
-    return m_data.Compare (HighPrecision::Zero ()) > 0;
+    return From (HighPrecision (value), timeUnit);
   }
-  HighPrecision const &GetHighPrecision (void) const
+  /**
+   * \param time a Time object
+   * \param timeUnit the unit of the value to return
+   *
+   * Convert the input time into an integer value according to the requested
+   * time unit.
+   */
+  inline static uint64_t ToInteger (const Time &time, enum Unit timeUnit)
   {
-    return m_data;
+    struct Information *info = PeekInformation (timeUnit);
+    uint64_t v = time.m_data.GetInteger ();
+    if (info->toMul)
+      {
+        v *= info->factor;
+      }
+    else
+      {
+        v /= info->factor; 
+      }
+    return v;
   }
-  HighPrecision * PeekHighPrecision (void)
+  /**
+   * \param time a Time object
+   * \param timeUnit the unit of the value to return
+   *
+   * Convert the input time into a floating point value according to the requested
+   * time unit.
+   */
+  inline static double ToDouble (const Time &time, enum Unit timeUnit)
   {
-    return &m_data;
+    return To (time, timeUnit).GetDouble ();
   }
 
-  static uint64_t UnitsToTimestep (uint64_t unitValue,
-                                   uint64_t unitFactor);
+private:
+  struct Information
+  {
+    bool toMul;
+    bool fromMul;
+    uint64_t factor;
+    HighPrecision timeTo;
+    HighPrecision timeFrom;
+  };
+  struct Resolution
+  {
+    struct Information info[LAST];
+    enum Time::Unit unit;
+  };
 
-private:
+  static inline struct Resolution *PeekResolution (void)
+  {
+    static struct Time::Resolution resolution = GetNsResolution ();
+    return &resolution;
+  }
+  static inline struct Information *PeekInformation (enum Unit timeUnit)
+  {
+    return &(PeekResolution ()->info[timeUnit]);
+  }
+  static inline Time From (HighPrecision tmp, enum Unit timeUnit)
+  {
+    struct Information *info = PeekInformation (timeUnit);
+    if (info->fromMul)
+      {
+        tmp.Mul (info->timeFrom);
+      }
+    else
+      {
+        tmp.MulByInvert (info->timeFrom);
+      }
+    return Time (tmp);
+  }
+  static inline HighPrecision To (const Time &time, enum Unit timeUnit)
+  {
+    struct Information *info = PeekInformation (timeUnit);
+    HighPrecision tmp = time.GetHighPrecision ();
+    if (info->toMul)
+      {
+        tmp.Mul (info->timeTo);
+      }
+    else
+      {
+        tmp.MulByInvert (info->timeTo);
+      }
+    return tmp;
+  }
+
+  static struct Resolution GetNsResolution (void);
+  static void SetResolution (enum Unit unit, struct Resolution *resolution);
+
   HighPrecision m_data;
+};
 
-  /*
-   * \Returns the value of time_value in units of unitPrec. time_value
-   * must be specified in timestep units (which are the same as the
-   * m_tsPrecision units
-   */
-  int64_t ConvertToUnits (int64_t timeValue, uint64_t unitFactor) const;
-};
+inline bool
+operator == (Time const &lhs, Time const &rhs)
+{
+  return lhs.Compare (rhs) == 0;
+}
+inline bool
+operator != (Time const &lhs, Time const &rhs)
+{
+  return lhs.Compare (rhs) != 0;
+}
+inline bool
+operator <= (Time const &lhs, Time const &rhs)
+{
+  return lhs.Compare (rhs) <= 0;
+}
+inline bool
+operator >= (Time const &lhs, Time const &rhs)
+{
+  return lhs.Compare (rhs) >= 0;
+}
+inline bool
+operator < (Time const &lhs, Time const &rhs)
+{
+  return lhs.Compare (rhs) < 0;
+}
+inline bool
+operator > (Time const &lhs, Time const &rhs)
+{
+  return lhs.Compare (rhs) > 0;
+}
+inline Time operator + (Time const &lhs, Time const &rhs)
+{
+  HighPrecision retval = lhs.GetHighPrecision ();
+  retval.Add (rhs.GetHighPrecision ());
+  return Time (retval);
+}
+inline Time operator - (Time const &lhs, Time const &rhs)
+{
+  HighPrecision retval = lhs.GetHighPrecision ();
+  retval.Sub (rhs.GetHighPrecision ());
+  return Time (retval);
+}
+inline Time operator * (Time const &lhs, Time const &rhs)
+{
+  HighPrecision retval = lhs.GetHighPrecision ();
+  retval.Mul (rhs.GetHighPrecision ());
+  return Time (retval);
+}
+inline Time operator / (Time const &lhs, Time const &rhs)
+{
+  NS_ASSERT (rhs.GetHighPrecision ().GetDouble () != 0);
+  HighPrecision retval = lhs.GetHighPrecision ();
+  retval.Div (rhs.GetHighPrecision ());
+  return Time (retval);
+}
+inline Time &operator += (Time &lhs, Time const &rhs)
+{
+  HighPrecision *lhsv = lhs.PeekHighPrecision ();
+  lhsv->Add (rhs.GetHighPrecision ());
+  return lhs;
+}
+inline Time &operator -= (Time &lhs, Time const &rhs)
+{
+  HighPrecision *lhsv = lhs.PeekHighPrecision ();
+  lhsv->Sub (rhs.GetHighPrecision ());
+  return lhs;
+}
+inline Time &operator *= (Time &lhs, Time const &rhs)
+{
+  HighPrecision *lhsv = lhs.PeekHighPrecision ();
+  lhsv->Mul (rhs.GetHighPrecision ());
+  return lhs;
+}
+inline Time &operator /= (Time &lhs, Time const &rhs)
+{
+  HighPrecision *lhsv = lhs.PeekHighPrecision ();
+  lhsv->Div (rhs.GetHighPrecision ());
+  return lhs;
+}
+
 
 /**
- * \brief keep track of seconds.
- *
- * This is an instance of type ns3::TimeUnit<1>: it is
- * the return value of the ns3::Simulator::Now method
- * and is needed for the Simulator::Schedule methods.
- * The precision of the underlying Time unit can be
- * changed with calls to TimeStepPrecision::Set.
- *
- * Time instances can be created through any of the following functions:
- *  - ns3::Seconds
- *  - ns3::MilliSeconds
- *  - ns3::MicroSeconds
- *  - ns3::NanoSeconds
- *  - ns3::PicoSeconds
- *  - ns3::FemtoSeconds
- *  - ns3::Now
- *
- * Time instances can be added, substracted, multipled and divided using
- * the standard C++ operators (if you make sure to obey the rules
- * of the ns3::TimeUnit class template)
- * To scale a Time instance, you can multiply it with an instance of
- * the ns3::Scalar class.
- * Time instances can also be manipulated through the following non-member
- * functions:
- *  - \ref ns3-Time-Abs ns3::Abs
- *  - \ref ns3-Time-Max ns3::Max
- *  - \ref ns3-Time-Min ns3::Min
- *
- * The Time class has the following additional methods not available in
- * the generic TimeUnit template:
- *
- * \code
- * double GetSeconds (void) const;
- * \endcode
- * returns an approximation in seconds of the time stored in this
- *          instance.
- *
- * \code
- * int64_t GetMilliSeconds (void) const;
- * \endcode
- * returns an approximation in milliseconds of the time stored in this
- *          instance.
- *
- * \code
- * int64_t GetMicroSeconds (void) const;
- * \endcode
- * returns an approximation in microseconds of the time stored in this
- *          instance.
- *
- * \code
- * int64_t GetNanoSeconds (void) const;
- * \endcode
- * returns an approximation in nanoseconds of the time stored in this
- *          instance.
- *
- * \code
- * int64_t GetPicoSeconds (void) const;
- * \endcode
- * returns an approximation in picoseconds of the time stored in this
- *          instance.
- *
- * \code
- * int64_t GetFemtoSeconds (void) const;
- * \endcode
- * returns an approximation in femtoseconds of the time stored in this
- *          instance.
+ * \anchor ns3-Time-Abs
+ * \relates ns3::TimeUnit
+ * \param time the input value
+ * \returns the absolute value of the input value.
+ */
+inline Time Abs (Time const &time)
+{
+  return Time (Abs (time.GetHighPrecision ()));
+}
+/**
+ * \anchor ns3-Time-Max
+ * \relates ns3::TimeUnit
+ * \param ta the first value
+ * \param tb the seconds value
+ * \returns the max of the two input values.
  */
-typedef TimeUnit<1> Time;
+inline Time Max (Time const &ta, Time const &tb)
+{
+  HighPrecision a = ta.GetHighPrecision ();
+  HighPrecision b = tb.GetHighPrecision ();
+  return Time (Max (a, b));
+}
+/**
+ * \anchor ns3-Time-Min
+ * \relates ns3::TimeUnit
+ * \param ta the first value
+ * \param tb the seconds value
+ * \returns the min of the two input values.
+ */
+inline Time Min (Time const &ta, Time const &tb)
+{
+  HighPrecision a = ta.GetHighPrecision ();
+  HighPrecision b = tb.GetHighPrecision ();
+  return Time (Min (a, b));
+}
 
 
 std::ostream& operator<< (std::ostream& os, const Time & time);
@@ -551,7 +580,10 @@
  * \endcode
  * \param seconds seconds value
  */
-Time Seconds (double seconds);
+inline Time Seconds (double seconds)
+{
+  return Time::FromDouble (seconds, Time::S);
+}
 
 /**
  * \brief create ns3::Time instances in units of milliseconds.
@@ -563,7 +595,10 @@
  * \endcode
  * \param ms milliseconds value
  */
-Time MilliSeconds (uint64_t ms);
+inline Time MilliSeconds (uint64_t ms)
+{
+  return Time::FromInteger (ms, Time::MS);
+}
 /**
  * \brief create ns3::Time instances in units of microseconds.
  *
@@ -574,7 +609,10 @@
  * \endcode
  * \param us microseconds value
  */
-Time MicroSeconds (uint64_t us);
+inline Time MicroSeconds (uint64_t us)
+{
+  return Time::FromInteger (us, Time::US);
+}
 /**
  * \brief create ns3::Time instances in units of nanoseconds.
  *
@@ -585,7 +623,10 @@
  * \endcode
  * \param ns nanoseconds value
  */
-Time NanoSeconds (uint64_t ns);
+inline Time NanoSeconds (uint64_t ns)
+{
+  return Time::FromInteger (ns, Time::NS);
+}
 /**
  * \brief create ns3::Time instances in units of picoseconds.
  *
@@ -596,7 +637,10 @@
  * \endcode
  * \param ps picoseconds value
  */
-Time PicoSeconds (uint64_t ps);
+inline Time PicoSeconds (uint64_t ps)
+{
+  return Time::FromInteger (ps, Time::PS);
+}
 /**
  * \brief create ns3::Time instances in units of femtoseconds.
  *
@@ -607,104 +651,55 @@
  * \endcode
  * \param fs femtoseconds value
  */
-Time FemtoSeconds (uint64_t fs);
+inline Time FemtoSeconds (uint64_t fs)
+{
+  return Time::FromInteger (fs, Time::FS);
+}
 
 // internal function not publicly documented
-Time TimeStep (uint64_t ts);
-
-// Explicit instantiation of the TimeUnit template for N=0, with a few
-// additional methods that should not be available for N != 0
-template <>
-class TimeUnit<0>
+inline Time TimeStep (uint64_t ts)
 {
-  // -*- New methods -*-
-public:
-  double GetDouble (void) const;
-  TimeUnit<0> (double scalar);
+  return Time (HighPrecision (ts, false));
+}
 
-  // -*- The rest is the the same as in the generic template class -*-
+class Scalar
+{
 public:
-  TimeUnit ()
-    : m_data ()
-  {
-  }
-  TimeUnit (TimeUnit const &o)
-    : m_data (o.m_data)
+  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 ()
   {
-  }
-  TimeUnit operator = (TimeUnit const &o)
-  {
-    m_data = o.m_data;
-    return *this;
-  }
-  TimeUnit (HighPrecision data)
-    : m_data (data)
-  {
+    return Time (HighPrecision (m_v));
   }
-  bool IsZero (void) const
-  {
-    return m_data.Compare (HighPrecision::Zero ()) == 0;
-  }
-  bool IsNegative (void) const
+  inline double GetDouble (void) const
   {
-    return m_data.Compare (HighPrecision::Zero ()) <= 0;
-  }
-  bool IsPositive (void) const
-  {
-    return m_data.Compare (HighPrecision::Zero ()) >= 0;
-  }
-  bool IsStrictlyNegative (void) const
-  {
-    return m_data.Compare (HighPrecision::Zero ()) < 0;
+    return m_v;
   }
-  bool IsStrictlyPositive (void) const
-  {
-    return m_data.Compare (HighPrecision::Zero ()) > 0;
-  }
-  HighPrecision const &GetHighPrecision (void) const
-  {
-    return m_data;
-  }
-  HighPrecision * PeekHighPrecision (void)
-  {
-    return &m_data;
-  }
-
 private:
-  HighPrecision m_data;
+  double m_v;
 };
 
-/**
- * \brief hold scalar values
- *
- * This class is used both to construct scalar values to multiply
- * ns3::Time instances and to hold the return value of
- * an expression which returns a scalar. For example, the
- * following code will output on your terminal 1.5:
- * \code
- * Scalar s0 = Scalar (1.5);
- * Time t1 = Seconds (10.0) * s0;
- * Time t2 = Seconds (10.0) * Scalar (2.5);
- * Scalar s1 = Seconds (15.0) / Seconds (10.0);
- * std::cout << s1.GetDouble () << std::endl;
- * \endcode
- *
- * The Scalar class has the following additional methods not available in
- * the generic TimeUnit template:
- * \code
- * double GetDouble (void) const;
- * \endcode
- * returns the C double contained in the Scalar instance
- *
- * \code
- * Scalar(double scalar);
- * \endcode
- * Constructs a Scalar instance from a C double.
- */
-typedef TimeUnit<0> Scalar;
-
-typedef TimeUnit<-1> TimeInvert;
-typedef TimeUnit<2> TimeSquare;
+typedef Time TimeInvert;
+typedef Time TimeSquare;
 
 /**
  * \class ns3::TimeValue
@@ -712,8 +707,8 @@
  */
 
 
+ATTRIBUTE_VALUE_DEFINE (Time);
 ATTRIBUTE_ACCESSOR_DEFINE (Time);
-ATTRIBUTE_VALUE_DEFINE (Time);
 ATTRIBUTE_CHECKER_DEFINE (Time);
 
 } // namespace ns3
--- a/src/simulator/realtime-simulator-impl.cc	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/realtime-simulator-impl.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -45,7 +45,7 @@
 RealtimeSimulatorImpl::GetTypeId (void)
 {
   static TypeId tid = TypeId ("ns3::RealtimeSimulatorImpl")
-    .SetParent<Object> ()
+    .SetParent<SimulatorImpl> ()
     .AddConstructor<RealtimeSimulatorImpl> ()
     .AddAttribute ("SynchronizationMode", 
                    "What to do if the simulation cannot keep up with real time.",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/simulator-impl.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -0,0 +1,14 @@
+#include "simulator-impl.h"
+
+namespace ns3 {
+
+TypeId 
+SimulatorImpl::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::SimulatorImpl")
+    .SetParent<Object> ()
+    ;
+  return tid;
+}
+
+} // namespace ns3
--- a/src/simulator/simulator-impl.h	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/simulator-impl.h	Sat Aug 07 14:30:18 2010 +0200
@@ -35,6 +35,8 @@
 class SimulatorImpl : public Object
 {
 public:
+  static TypeId GetTypeId (void);
+
   /**
    * Every event scheduled by the Simulator::insertAtDestroy method is
    * invoked. Then, we ensure that any memory allocated by the 
--- a/src/simulator/synchronizer.cc	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/synchronizer.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -112,49 +112,15 @@
   uint64_t
 Synchronizer::TimeStepToNanosecond (uint64_t ts)
 {
-  switch (TimeStepPrecision::Get ()) {
-  case TimeStepPrecision::S:
-    return ts * 1000000000;
-  case TimeStepPrecision::MS:
-    return ts * 1000000;
-  case TimeStepPrecision::US:
-    return ts * 1000;
-  case TimeStepPrecision::NS:
-    return ts;
-  case TimeStepPrecision::PS:
-    return ts / 1000;
-  case TimeStepPrecision::FS:
-    return ts / 1000000;
-  default:
-    NS_ASSERT_MSG (false, "Synchronizer::TimeStepToNanosecond: "
-        "Unexpected precision not implemented");
-    return 0;
-  }
+  return TimeStep (ts).GetNanoSeconds ();
 }
 
   uint64_t
 Synchronizer::NanosecondToTimeStep (uint64_t ns)
 {
-  switch (TimeStepPrecision::Get ()) {
-  case TimeStepPrecision::S:
-    return ns / 1000000000;
-  case TimeStepPrecision::MS:
-    return ns / 1000000;
-  case TimeStepPrecision::US:
-    return ns / 1000;
-  case TimeStepPrecision::NS:
-    return ns;
-  case TimeStepPrecision::PS:
-    return ns * 1000;
-  case TimeStepPrecision::FS:
-    return ns * 1000000;
-  default:
-    NS_ASSERT_MSG (false, "Synchronizer::NanosecondToTimeStep: "
-        "Unexpected precision not implemented");
-    return 0;
-  }
+  return NanoSeconds (ns).GetTimeStep ();
 }
 
-}; // namespace ns3
+} // namespace ns3
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/time-base.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -0,0 +1,59 @@
+#include "time-base.h"
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+struct TimeBase::Resolution
+TimeBase::GetNsResolution (void)
+{  
+  struct Resolution resolution;
+  SetResolution (TimeBase::NS, &resolution);
+  return resolution;
+}
+void 
+TimeBase::SetResolution (enum Unit resolution)
+{
+  SetResolution (resolution, PeekResolution ());
+}
+void 
+TimeBase::SetResolution (enum Unit unit, struct Resolution *resolution)
+{
+  int8_t power [LAST] = {15, 12, 9, 6, 3, 0};
+  for (int i = 0; i < TimeBase::LAST; i++)
+    {
+      int shift = power[i] - power[(int)unit];
+      uint64_t factor = (uint64_t) pow (10, fabs (shift));
+      struct Information *info = &resolution->info[i];
+      info->factor = factor;
+      if (shift == 0)
+	{
+	  info->timeFrom = HighPrecision (1, false);
+	  info->timeTo = HighPrecision (1, false);
+	  info->toMul = true;
+	  info->fromMul = true;
+	}
+      else if (shift > 0)
+	{
+	  info->timeFrom = HighPrecision (factor, false);
+	  info->timeTo = HighPrecision::Invert (factor);
+	  info->toMul = false;
+	  info->fromMul = true;
+	}
+      else
+	{
+	  NS_ASSERT (shift < 0);
+	  info->timeFrom = HighPrecision::Invert (factor);
+	  info->timeTo = HighPrecision (factor, false);
+	  info->toMul = true;
+	  info->fromMul = false;
+	}
+    }
+  resolution->unit = unit;
+}
+enum TimeBase::Unit
+TimeBase::GetResolution (void)
+{
+  return PeekResolution ()->unit;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/time-base.h	Sat Aug 07 14:30:18 2010 +0200
@@ -0,0 +1,336 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,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 TIME_BASE_H
+#define TIME_BASE_H
+
+#include "high-precision.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup time
+ * \brief keep track of global simulation resolution
+ *
+ * This class is the base class for all time-related classes. It controls
+ * the resolution of the underlying time value . The default resolution
+ * is nanoseconds. That is, TimeStep (1).GetNanoSeconds () will return
+ * 1. It is possible to either increase or decrease the resolution and the
+ * code tries really hard to make this easy.
+ *
+ * If your resolution is X (say, nanoseconds) and if you create Time objects 
+ * with a lower resolution (say, picoseconds), don't expect that this 
+ * code will return 1: PicoSeconds (1).GetPicoSeconds (). It will most 
+ * likely return 0 because the Time object has only 64 bits of fractional 
+ * precision which means that PicoSeconds (1) is stored as a 64-bit aproximation
+ * of 1/1000 in the Time object. If you later multiply it again by the exact 
+ * value 1000, the result is unlikely to be 1 exactly. It will be close to
+ * 1 but not exactly 1.
+ * 
+ * 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
+ * to switch the global resolution to picoseconds to avoid nasty surprises.
+ *
+ * Another important issue to keep in mind is that if you increase the
+ * global resolution, you also implicitely decrease the range of your simulation.
+ * i.e., the global simulation time is stored in a 64 bit integer whose interpretation
+ * will depend on the global resolution so, 2^64 picoseconds which is the maximum
+ * duration of your simulation if the global resolution is picoseconds 
+ * is smaller than 2^64 nanoseconds which is the maximum duration of your simulation
+ * if the global resolution is nanoseconds.
+ *
+ * Finally, don't even think about ever changing the global resolution after
+ * creating Time objects: all Time objects created before the call to SetResolution
+ * will contain values which are not updated to the new resolution. In practice,
+ * the default value for the attributes of many models is indeed calculated
+ * before the main function of the main program enters. Because of this, if you
+ * use one of these models (and it's likely), it's going to be hard to change
+ * the global simulation resolution in a way which gives reasonable results. This
+ * issue has been filed as bug 954 in the ns-3 bugzilla installation.
+ */
+class TimeBase
+{
+public:
+  /**
+   * The unit to use to interpret a number representing time
+   */
+  enum Unit
+    {
+      S  = 0,
+      MS = 1,
+      US = 2,
+      NS = 3,
+      PS = 4,
+      FS = 5,
+      LAST = 6
+    };
+  /**
+   * \param resolution the new resolution to use
+   *
+   * Change the global resolution used to convert all 
+   * user-provided time values in Time objects and Time objects
+   * in user-expected time units.
+   */
+  static void SetResolution (enum Unit resolution);
+  /**
+   * \returns the current global resolution.
+   */
+  static enum Unit GetResolution (void);
+  /**
+   * \param value to convert into a Time object
+   * \param timeUnit the unit of the value to convert
+   * \return a new Time object
+   *
+   * This method interprets the input value according to the input
+   * unit and constructs a matching Time object.
+   *
+   * \sa FromDouble, ToDouble, ToInteger
+   */
+  inline static TimeBase FromInteger (uint64_t value, enum Unit timeUnit);
+  /**
+   * \param value to convert into a Time object
+   * \param timeUnit the unit of the value to convert
+   * \return a new Time object
+   *
+   * \sa FromInteger, ToInteger, ToDouble
+   */
+  inline static TimeBase FromDouble (double value, enum Unit timeUnit);
+  /**
+   * \param time a Time object
+   * \param timeUnit the unit of the value to return
+   *
+   * Convert the input time into an integer value according to the requested
+   * time unit.
+   */
+  inline static uint64_t ToInteger (const TimeBase &time, enum Unit timeUnit);
+  /**
+   * \param time a Time object
+   * \param timeUnit the unit of the value to return
+   *
+   * Convert the input time into a floating point value according to the requested
+   * time unit.
+   */
+  inline static double ToDouble (const TimeBase &time, enum Unit timeUnit);
+
+  inline TimeBase ();
+  inline TimeBase (const TimeBase &o);
+  inline TimeBase operator = (const TimeBase &o);
+  inline TimeBase (const HighPrecision &data);
+  /**
+   * \return true if the time is zero, false otherwise.
+   */
+  inline bool IsZero (void) const;
+  /**
+   * \return true if the time is negative or zero, false otherwise.
+   */
+  inline bool IsNegative (void) const;
+  /**
+   * \return true if the time is positive or zero, false otherwise.
+   */
+  inline bool IsPositive (void) const;
+  /**
+   * \return true if the time is strictly negative, false otherwise.
+   */
+  inline bool IsStrictlyNegative (void) const;
+  /**
+   * \return true if the time is strictly positive, false otherwise.
+   */
+  inline bool IsStrictlyPositive (void) const;
+
+  /**
+   * 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;
+  inline HighPrecision * PeekHighPrecision (void);
+
+protected:
+  HighPrecision m_data;
+private:
+  struct Information
+  {
+    bool toMul;
+    bool fromMul;
+    uint64_t factor;
+    HighPrecision timeTo;
+    HighPrecision timeFrom;
+  };
+  struct Resolution
+  {
+    struct Information info[LAST];
+    enum TimeBase::Unit unit;
+  };
+
+  inline static struct Resolution *PeekResolution (void);
+  inline static struct Information *PeekInformation (enum Unit timeUnit);
+  static struct Resolution GetNsResolution (void);
+  static void SetResolution (enum Unit unit, struct Resolution *resolution);
+  inline static TimeBase From (HighPrecision tmp, enum Unit timeUnit);
+  inline static HighPrecision To (const TimeBase &time, enum Unit timeUnit);
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+TimeBase::TimeBase ()
+  : m_data ()
+{
+}
+TimeBase::TimeBase (const TimeBase &o)
+  : m_data (o.m_data)
+{
+}
+TimeBase TimeBase::operator = (const TimeBase &o)
+{
+  m_data = o.m_data;
+  return *this;
+}
+TimeBase::TimeBase (const HighPrecision &data)
+  : m_data (data)
+{
+}
+
+HighPrecision const &
+TimeBase::GetHighPrecision (void) const
+{
+  return m_data;
+}
+
+HighPrecision *
+TimeBase::PeekHighPrecision (void)
+{
+  return &m_data;
+}
+
+bool
+TimeBase::IsZero (void) const
+{
+  return m_data.Compare (HighPrecision::Zero ()) == 0;
+}
+
+bool
+TimeBase::IsNegative (void) const
+{
+  return m_data.Compare (HighPrecision::Zero ()) <= 0;
+}
+
+bool
+TimeBase::IsPositive (void) const
+{
+  return m_data.Compare (HighPrecision::Zero ()) >= 0;
+}
+
+bool
+TimeBase::IsStrictlyNegative (void) const
+{
+  return m_data.Compare (HighPrecision::Zero ()) < 0;
+}
+
+bool
+TimeBase::IsStrictlyPositive (void) const
+{
+  return m_data.Compare (HighPrecision::Zero ()) > 0;
+}
+
+struct TimeBase::Resolution *
+TimeBase::PeekResolution (void)
+{
+  static struct TimeBase::Resolution resolution = GetNsResolution ();
+  return &resolution;
+}
+struct TimeBase::Information *
+TimeBase::PeekInformation (enum Unit timeUnit)
+{
+  return &(PeekResolution ()->info[timeUnit]);
+}
+TimeBase 
+TimeBase::From (HighPrecision tmp, enum Unit timeUnit)
+{
+  struct Information *info = PeekInformation (timeUnit);
+  if (info->fromMul)
+    {
+      tmp.Mul (info->timeFrom);
+    }
+  else
+    {
+      tmp.MulByInvert (info->timeFrom);
+    }
+  return TimeBase (tmp);
+}
+HighPrecision
+TimeBase::To (const TimeBase &time, enum Unit timeUnit)
+{
+  struct Information *info = PeekInformation (timeUnit);
+  HighPrecision tmp = time.GetHighPrecision ();
+  if (info->toMul)
+    {
+      tmp.Mul (info->timeTo);
+    }
+  else
+    {
+      tmp.MulByInvert (info->timeTo);
+    }
+  return tmp;
+}
+
+TimeBase
+TimeBase::FromInteger (uint64_t value, enum Unit timeUnit)
+{
+  struct Information *info = PeekInformation (timeUnit);
+  if (info->fromMul)
+    {
+      value *= info->factor;
+      return TimeBase (HighPrecision (value, false));
+    }
+  return From (HighPrecision (value, false), timeUnit);
+}
+TimeBase
+TimeBase::FromDouble (double value, enum Unit timeUnit)
+{
+  return From (HighPrecision (value), timeUnit);
+}
+uint64_t 
+TimeBase::ToInteger (const TimeBase &time, enum Unit timeUnit)
+{
+  struct Information *info = PeekInformation (timeUnit);
+  uint64_t v = time.m_data.GetInteger ();
+  if (info->toMul)
+    {
+      v *= info->factor;
+    }
+  else
+    {
+      v /= info->factor; 
+    }
+  return v;
+}
+double 
+TimeBase::ToDouble (const TimeBase &time, enum Unit timeUnit)
+{
+  return To (time, timeUnit).GetDouble ();
+}
+
+} // namespace ns3
+
+#endif /* TIME_BASE_H */
--- a/src/simulator/time.cc	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/time.cc	Sat Aug 07 14:30:18 2010 +0200
@@ -20,54 +20,18 @@
  * TimeStep support by Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
  */
 #include "nstime.h"
-#include "ns3/fatal-error.h"
+#include "ns3/abort.h"
 #include "ns3/global-value.h"
 #include "ns3/enum.h"
 #include "ns3/string.h"
 #include "ns3/object.h"
 #include "ns3/config.h"
 #include <math.h>
+#include <sstream>
 
 namespace ns3 {
 
-namespace TimeStepPrecision {
-
-static const uint64_t MS_FACTOR = (uint64_t)1000;
-static const uint64_t US_FACTOR = (uint64_t)1000000;
-static const uint64_t NS_FACTOR = (uint64_t)1000000 * (uint64_t)1000;
-static const uint64_t PS_FACTOR = (uint64_t)1000000 * (uint64_t)1000000;
-static const uint64_t FS_FACTOR = (uint64_t)1000000 * (uint64_t)1000000 * (uint64_t)1000;
-static uint64_t g_tsPrecFactor = NS_FACTOR;
-
-static GlobalValue g_precisionDefaultValue ("TimeStepPrecision",
-                                            "The time unit of the internal 64 bit integer time.",
-                                            EnumValue (NS),
-                                            MakeEnumChecker (NS, "NS",
-                                                             S, "S",
-                                                             MS, "MS",
-                                                             US, "US",
-                                                             PS, "PS",
-                                                             FS, "FS")
-                                            );
-
-precision_t
-Get (void)
-{
-  EnumValue v;
-  g_precisionDefaultValue.GetValue (v);
-  return (precision_t) v.Get ();
-}
-
-void
-Set (precision_t precision)
-{
-  g_precisionDefaultValue.SetValue (EnumValue (precision));
-  g_tsPrecFactor = (uint64_t)pow (10, precision);
-}
-
-} // namespace TimeStepPrecision
-
-TimeUnit<1>::TimeUnit (const std::string& s)
+Time::Time (const std::string& s)
 {
   std::string::size_type n = s.find_first_not_of ("0123456789.");
   if (n != std::string::npos)
@@ -79,40 +43,35 @@
       std::string trailer = s.substr (n, std::string::npos);
       if (trailer == std::string ("s"))
         {
-          m_data = HighPrecision (r * TimeStepPrecision::g_tsPrecFactor);
+          *this = Time::FromDouble (r, Time::S);
           return;
         }
       if (trailer == std::string ("ms"))
         {
-          m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,3))),
-                                  false);
+          *this = Time::FromDouble (r, Time::MS);
           return;
         }
       if (trailer == std::string ("us"))
         {
-          m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,6))),
-                                  false);
+          *this = Time::FromDouble (r, Time::US);
           return;
         }
       if (trailer == std::string ("ns"))
         {
-          m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,9))),
-                                  false);
+          *this = Time::FromDouble (r, Time::NS);
           return;
         }
       if (trailer == std::string ("ps"))
         {
-          m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,12))),
-                                  false);
+          *this = Time::FromDouble (r, Time::PS);
           return;
         }
       if (trailer == std::string ("fs"))
         {
-          m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,15))),
-                                  false);
+          *this = Time::FromDouble (r, Time::FS);
           return;
         }
-      NS_FATAL_ERROR ("Can't Parse Time " << s);
+      NS_ABORT_MSG ("Can't Parse Time " << s);
     }
   // else
   // they didn't provide units, assume seconds
@@ -120,84 +79,60 @@
   iss.str (s);
   double v;
   iss >> v;
-  m_data = HighPrecision (v * TimeStepPrecision::g_tsPrecFactor);
-}
-
-double
-TimeUnit<1>::GetSeconds (void) const
-{
-  double timeValue = GetHighPrecision ().GetDouble ();
-  return timeValue / TimeStepPrecision::g_tsPrecFactor;
-}
-
-int64_t
-TimeUnit<1>::ConvertToUnits (int64_t timeValue, uint64_t unitFactor) const
-{
-  uint64_t precFactor;
-  // In order to avoid conversion to double, precFactor can't be less 1
-  if (TimeStepPrecision::g_tsPrecFactor < unitFactor)
-    {
-      precFactor = unitFactor / TimeStepPrecision::g_tsPrecFactor;
-      timeValue = timeValue * precFactor;
-    }
-  else
-    {
-      precFactor = TimeStepPrecision::g_tsPrecFactor / unitFactor;
-      timeValue = timeValue / precFactor;
-    }
-  return timeValue;
+  *this = Time::FromDouble (v, Time::S);
 }
 
-
-int64_t
-TimeUnit<1>::GetMilliSeconds (void) const
-{
-  int64_t ts = GetTimeStep ();
-  int64_t ms = ConvertToUnits (ts, TimeStepPrecision::MS_FACTOR);
-
-  return ms;
+struct Time::Resolution
+Time::GetNsResolution (void)
+{  
+  struct Resolution resolution;
+  SetResolution (Time::NS, &resolution);
+  return resolution;
 }
-int64_t
-TimeUnit<1>::GetMicroSeconds (void) const
+void 
+Time::SetResolution (enum Unit resolution)
 {
-  int64_t ts = GetTimeStep ();
-  int64_t us = ConvertToUnits (ts, TimeStepPrecision::US_FACTOR);
-
-  return us;
-}
-int64_t
-TimeUnit<1>::GetNanoSeconds (void) const
-{
-  int64_t ts = GetTimeStep ();
-  int64_t ns = ConvertToUnits (ts, TimeStepPrecision::NS_FACTOR);
-
-  return ns;
+  SetResolution (resolution, PeekResolution ());
 }
-int64_t
-TimeUnit<1>::GetPicoSeconds (void) const
-{
-  int64_t ts = GetTimeStep ();
-  int64_t ps = ConvertToUnits (ts, TimeStepPrecision::PS_FACTOR);
-
-  return ps;
-}
-int64_t
-TimeUnit<1>::GetFemtoSeconds (void) const
+void 
+Time::SetResolution (enum Unit unit, struct Resolution *resolution)
 {
-  int64_t ts = GetTimeStep ();
-  int64_t fs = ConvertToUnits (ts, TimeStepPrecision::FS_FACTOR);
-
-  return fs;
+  int8_t power [LAST] = {15, 12, 9, 6, 3, 0};
+  for (int i = 0; i < Time::LAST; i++)
+    {
+      int shift = power[i] - power[(int)unit];
+      uint64_t factor = (uint64_t) pow (10, fabs (shift));
+      struct Information *info = &resolution->info[i];
+      info->factor = factor;
+      if (shift == 0)
+	{
+	  info->timeFrom = HighPrecision (1, false);
+	  info->timeTo = HighPrecision (1, false);
+	  info->toMul = true;
+	  info->fromMul = true;
+	}
+      else if (shift > 0)
+	{
+	  info->timeFrom = HighPrecision (factor, false);
+	  info->timeTo = HighPrecision::Invert (factor);
+	  info->toMul = false;
+	  info->fromMul = true;
+	}
+      else
+	{
+	  NS_ASSERT (shift < 0);
+	  info->timeFrom = HighPrecision::Invert (factor);
+	  info->timeTo = HighPrecision (factor, false);
+	  info->toMul = true;
+	  info->fromMul = false;
+	}
+    }
+  resolution->unit = unit;
 }
-
-/**
- * This returns the value with the precision returned by TimeStepPrecision::Get
- */
-int64_t
-TimeUnit<1>::GetTimeStep (void) const
+enum Time::Unit
+Time::GetResolution (void)
 {
-  int64_t timeValue = GetHighPrecision ().GetInteger ();
-  return timeValue;
+  return PeekResolution ()->unit;
 }
 
 
@@ -205,491 +140,52 @@
 operator<< (std::ostream& os, const Time & time)
 {
   std::string unit;
-  switch (TimeStepPrecision::Get ())
+  switch (Time::GetResolution ())
     {
-    case TimeStepPrecision::S:
+    case Time::S:
       unit = "s";
       break;
-    case TimeStepPrecision::MS:
+    case Time::MS:
       unit = "ms";
       break;
-    case TimeStepPrecision::US:
+    case Time::US:
       unit = "us";
       break;
-    case TimeStepPrecision::NS:
+    case Time::NS:
       unit = "ns";
       break;
-    case TimeStepPrecision::PS:
+    case Time::PS:
       unit = "ps";
       break;
-    case TimeStepPrecision::FS:
+    case Time::FS:
       unit = "fs";
       break;
+    case Time::LAST:
+      NS_ABORT_MSG ("can't be reached");
+      unit = "unreachable";
+      break;
     }
-  os << time.GetTimeStep () << unit;
+  double v = Time::ToDouble (time, Time::GetResolution ());
+  os << v << unit;
   return os;
 }
 std::istream& operator>> (std::istream& is, Time & time)
 {
   std::string value;
   is >> value;
-  std::string::size_type n = value.find_first_not_of ("0123456789.");
-  if (n == std::string::npos)
-    {
-      is.setstate (std::ios_base::failbit);
-      return is;
-    }
-  std::string trailer = value.substr (n, value.size () - n);
-  std::istringstream iss;
-  iss.str (value.substr (0, n));
-
-  if (trailer == std::string ("s"))
-    {
-      double v;
-      iss >> v;
-      time = Seconds (v);
-      return is;
-    }
-  uint64_t integer;
-  iss >> integer;
-  if (is.bad () || is.fail ())
-    {
-      is.setstate (std::ios_base::failbit);
-    }
-  else if (trailer == std::string ("ms"))
-    {
-      time = MilliSeconds (integer);
-    }
-  else if (trailer == std::string ("us"))
-    {
-      time = MicroSeconds (integer);
-    }
-  else if (trailer == std::string ("ns"))
-    {
-      time = NanoSeconds (integer);
-    }
-  else if (trailer == std::string ("ps"))
-    {
-      time = PicoSeconds (integer);
-    }
-  else if (trailer == std::string ("fs"))
-    {
-      time = FemtoSeconds (integer);
-    }
-  else
-    {
-      is.setstate (std::ios_base::failbit);
-    }
+  time = Time (value);
   return is;
 }
 
-Time Seconds (double seconds)
-{
-  double d_sec = seconds * TimeStepPrecision::g_tsPrecFactor;
-  return Time (HighPrecision (d_sec));
-  //  return Time (HighPrecision ((int64_t)d_sec, false));
-}
-
-uint64_t
-TimeUnit<1>::UnitsToTimestep (uint64_t unitValue,
-                              uint64_t unitFactor)
-{
-  uint64_t precFactor;
-  // In order to avoid conversion to double, precFactor can't be less 1
-  if (TimeStepPrecision::g_tsPrecFactor < unitFactor)
-    {
-      precFactor = unitFactor / TimeStepPrecision::g_tsPrecFactor;
-      unitValue = unitValue / precFactor;
-    }
-  else
-    {
-      precFactor = TimeStepPrecision::g_tsPrecFactor / unitFactor;
-      unitValue = unitValue * precFactor;
-    }
-  return unitValue;
-}
-
 ATTRIBUTE_VALUE_IMPLEMENT (Time);
 ATTRIBUTE_CHECKER_IMPLEMENT (Time);
 
-Time MilliSeconds (uint64_t ms)
-{
-  uint64_t ts = TimeUnit<1>::UnitsToTimestep (ms, TimeStepPrecision::MS_FACTOR);
-  return TimeStep (ts);
-}
-
-Time MicroSeconds (uint64_t us)
-{
-  uint64_t ts = TimeUnit<1>::UnitsToTimestep (us, TimeStepPrecision::US_FACTOR);
-  return TimeStep (ts);
-}
-
-Time NanoSeconds (uint64_t ns)
-{
-  uint64_t ts = TimeUnit<1>::UnitsToTimestep (ns, TimeStepPrecision::NS_FACTOR);
-  return TimeStep (ts);
-}
-Time PicoSeconds (uint64_t ps)
-{
-  uint64_t ts = TimeUnit<1>::UnitsToTimestep (ps, TimeStepPrecision::PS_FACTOR);
-  return TimeStep (ts);
-}
-Time FemtoSeconds (uint64_t fs)
-{
-  uint64_t ts = TimeUnit<1>::UnitsToTimestep (fs, TimeStepPrecision::FS_FACTOR);
-  return TimeStep (ts);
-}
-
-
-/*
- * The timestep value passed to this function must be of the precision
- * of TimeStepPrecision::Get
- */
-Time TimeStep (uint64_t ts)
-{
-  return Time (HighPrecision (ts, false));
-}
-
-TimeUnit<0>::TimeUnit (double scalar)
-  : m_data (HighPrecision (scalar))
-{
-}
-
-double
-TimeUnit<0>::GetDouble (void) const
-{
-  return GetHighPrecision ().GetDouble ();
-}
-
 } // namespace ns3
 
 #include "ns3/test.h"
 
 namespace ns3 {
 
-#define PRECISION(mult) (pow (10,-((double)(ns3::TimeStepPrecision::Get ()))) * mult)
-#define ASSERT_MSG_EQ(a,b,mult,msg)                                     \
-  NS_TEST_ASSERT_MSG_EQ (((a) < ((b) - PRECISION (mult)) || (a) > ((b) + PRECISION (mult))),false, \
-                         msg << " Values are not equal within requested precision range: " << \
-                         (a) << "!=" << (b) << " ~ " << PRECISION (mult))
-#define ASSERT_MSG_EQ_INT(a,b,mult,msg) \
-  ASSERT_MSG_EQ (((int64_t)(a)),((int64_t)(b)),mult,msg)
-#define ASSERT_EQ(a,b)                          \
-  ASSERT_MSG_EQ (a,b,1,"")
-
-class OldTimeTestCase : public TestCase
-{
-public:
-  OldTimeTestCase ();
-  virtual bool DoRun (void);
-};
-
-OldTimeTestCase::OldTimeTestCase ()
-  : TestCase ("Sanity check of common time operations")
-{
-}
-bool
-OldTimeTestCase::DoRun (void)
-{
-  NS_TEST_ASSERT_MSG_EQ (TimeStepPrecision::Get (),
-                         TimeStepPrecision::NS,
-                         "Invalid precision mode");
-
-  Time t0 = Seconds (10.0);
-  ASSERT_EQ (t0.GetSeconds (), 10.0);
-
-  Time t1 = Seconds (11.0);
-  ASSERT_EQ (t1.GetSeconds (), 11.0);
-
-  t0 = Seconds (1.5);
-  ASSERT_EQ (t0.GetSeconds (), 1.5);
-
-  t0 = Seconds (-1.5);
-  ASSERT_EQ (t0.GetSeconds (), -1.5);
-
-  t0 = MilliSeconds ((uint64_t)10.0);
-  ASSERT_EQ (t0.GetSeconds (), 0.01);
-
-  t1 = MilliSeconds ((uint64_t)11.0);
-  ASSERT_EQ (t1.GetSeconds (), 0.011);
-
-
-  Time t2, t3;
-
-  t2 = t1 - t0;
-  NS_TEST_ASSERT_MSG_EQ (t2.IsStrictlyPositive (),true, "Variable should be positive");
-  ASSERT_EQ (t2.GetSeconds (), t1.GetSeconds () - t0.GetSeconds ());
-
-  t2 = t1 - t1;
-  NS_TEST_ASSERT_MSG_EQ (t2.IsZero (),true, "Variable should be zero");
-  ASSERT_EQ (t2.GetSeconds (), t1.GetSeconds () - t1.GetSeconds ());
-
-  t2 = t0 - t1;
-  NS_TEST_ASSERT_MSG_EQ (t2.IsStrictlyNegative (),true, "Variable should be negative");
-  ASSERT_EQ (t2.GetSeconds (), t0.GetSeconds () - t1.GetSeconds ());
-
-  Time tmp = MilliSeconds (0);
-  NS_TEST_ASSERT_MSG_EQ ((MilliSeconds (0) == NanoSeconds (0)), true, "Zero is not Zero ?");
-  NS_TEST_ASSERT_MSG_EQ ((MilliSeconds (0) > NanoSeconds (0)), false, "Zero is bigger than Zero ?");
-  NS_TEST_ASSERT_MSG_EQ ((MilliSeconds (0) < NanoSeconds (0)), false, "Zero is smaller than Zero ?");
-
-  Time t4 = Seconds (10.0) * Scalar (1.5);
-  ASSERT_EQ (t4.GetSeconds (), 15.0);
-
-  Time t5 = NanoSeconds (10) * Scalar (1.5);
-  ASSERT_EQ (t5.GetNanoSeconds (), 15.0);
-
-  Time t6 = Seconds (10.0) * Scalar (15) / Scalar (10);
-  ASSERT_EQ (t6.GetSeconds (), 15.0);
-
-  Time t7 = NanoSeconds (10) * Scalar (15) / Scalar (10);
-  ASSERT_EQ (t7.GetNanoSeconds (), 15.0);
-
-  ASSERT_EQ ((t1 + t2).GetSeconds (), t1.GetSeconds () + t2.GetSeconds ());
-
-  ASSERT_EQ ((t1 / t2).GetDouble (), t1.GetSeconds () / t2.GetSeconds ());
-
-  return false;
-}
-
-class OperationsTimeTestCase : public TestCase
-{
-public:
-  OperationsTimeTestCase ();
-  virtual bool DoRun (void);
-};
-
-OperationsTimeTestCase::OperationsTimeTestCase ()
-  : TestCase ("Check the +, -, * and / operators for the TimeUnit<1>")
-{
-}
-
-bool
-OperationsTimeTestCase::DoRun (void)
-{
-  // What happens if you set these values ?
-  //  t0 = Seconds ((uint64_t)10.0);
-  //  t1 = Seconds ((uint64_t)11.0);
-
-  Time t0 = MilliSeconds (10);
-  Time t1 = MilliSeconds (11);
-
-  ASSERT_EQ ((t0 - t1).GetSeconds (),
-             (t0.GetSeconds () - t1.GetSeconds ()));
-  ASSERT_EQ (((t0 - t1) * t0 / t0).GetSeconds (),
-             ((t0.GetSeconds () - t1.GetSeconds ()) * t0.GetSeconds () / t0.GetSeconds ()));
-  ASSERT_EQ (((t0 - t1) * t0 / t1).GetSeconds (),
-             ((t0.GetSeconds () - t1.GetSeconds ()) * t0.GetSeconds () / t1.GetSeconds ()));
-  ASSERT_EQ ((t0 * (t0 - t1) / t1).GetSeconds (),
-             (t0.GetSeconds () * (t0.GetSeconds () - t1.GetSeconds ()) / t1.GetSeconds ()));
-  ASSERT_EQ ((t0 * t1 / (t0 - t1)).GetSeconds (),
-             (t0.GetSeconds () * t1.GetSeconds () / (t0.GetSeconds () - t1.GetSeconds ())));
-  ASSERT_EQ ((t0 * (t1 / (t0 - t1))).GetSeconds (),
-             (t0.GetSeconds () * (t1.GetSeconds () / (t0.GetSeconds () - t1.GetSeconds ()))));
-  ASSERT_EQ (((t0 * t1) / (t0 - t1)).GetSeconds (),
-             ((t0.GetSeconds () * t1.GetSeconds ()) / (t0.GetSeconds () - t1.GetSeconds ())));
-  ASSERT_EQ ((t0 / t1 * (t0 - t1)).GetSeconds (),
-             (t0.GetSeconds () / t1.GetSeconds () * (t0.GetSeconds () - t1.GetSeconds ())));
-  ASSERT_EQ (((t0 / t1) * (t0 - t1)).GetSeconds (),
-             (t0.GetSeconds () / t1.GetSeconds ()) * (t0.GetSeconds () - t1.GetSeconds ()));
-  ASSERT_EQ ((t0 * Scalar (10.0)).GetSeconds (), (t0.GetSeconds () * 10.0));
-  ASSERT_EQ ((Scalar (10.0) * t0).GetSeconds (), (10.0 * t0.GetSeconds ()));
-
-  // Note: we need to multiply by 1e9 because GetSeconds is multiplying
-  ASSERT_EQ (((t0 / (t1 * (t0 - t1))).GetHighPrecision ().GetDouble () * 1e9),
-             (t0.GetSeconds () / (t1.GetSeconds () * (t0.GetSeconds () - t1.GetSeconds ()))));
-
-  ASSERT_EQ ((t0 / t1).GetDouble (),(t0.GetSeconds () / t1.GetSeconds ()));
-
-
-  ASSERT_EQ ((t0 * t1 / ((t0 - t1) * t0)).GetDouble (),
-             (t0.GetSeconds () * t1.GetSeconds () / ((t0.GetSeconds () - t1.GetSeconds ()) * t0.GetSeconds ())));
-  return false;
-}
-
-class TimeStepTestCase : public TestCase
-{
-public:
-  TimeStepTestCase ();
-  virtual bool DoRun (void);
-};
-
-TimeStepTestCase::TimeStepTestCase ()
-  : TestCase ("Check boundaries of TimeStep")
-{
-}
-bool
-TimeStepTestCase::DoRun (void)
-{
-  Time tooBig = TimeStep (0x8000000000000000LL);
-  NS_TEST_ASSERT_MSG_EQ (tooBig.IsNegative (), true, "Is not negative ?");
-  tooBig = TimeStep (0xffffffffffffffffLL);
-  NS_TEST_ASSERT_MSG_EQ (tooBig.IsNegative (), true, "Is not negative ?");
-  tooBig = TimeStep (0x7fffffffffffffffLL);
-  NS_TEST_ASSERT_MSG_EQ (tooBig.IsPositive (), true, "Is not negative ?");
-  tooBig += TimeStep (1);
-  NS_TEST_ASSERT_MSG_EQ (tooBig.IsNegative (), true, "Is not negative ?");
-  return false;
-}
-
-class GlobalPrecisionTestCase : public TestCase
-{
-public:
-  GlobalPrecisionTestCase ();
-  virtual bool DoRun (void);
-  virtual void DoTeardown (void);
-};
-
-GlobalPrecisionTestCase::GlobalPrecisionTestCase ()
-  : TestCase ("Check that global value actually changes the underlying precision")
-{
-}
-#define CHECK_PRECISION(prec) \
-  Config::SetGlobal ("TimeStepPrecision", StringValue (# prec)); \
-  NS_TEST_ASSERT_MSG_EQ (TimeStepPrecision::Get (), TimeStepPrecision::prec, "Could not set precision " << # prec)
-bool
-GlobalPrecisionTestCase::DoRun (void)
-{
-  CHECK_PRECISION (S);
-  CHECK_PRECISION (MS);
-  CHECK_PRECISION (US);
-  CHECK_PRECISION (NS);
-  CHECK_PRECISION (PS);
-  CHECK_PRECISION (FS);
-  return false;
-}
-
-void
-GlobalPrecisionTestCase::DoTeardown (void)
-{
-  TimeStepPrecision::Set (TimeStepPrecision::NS);
-}
-
-#if 0
-// disable this test because it triggers crazy
-// compiler behavior (ICE+unbounded memory usage)
-class ConversionTestCase : public TestCase
-{
-public:
-  ConversionTestCase ();
-  virtual bool DoRun (void);
-  virtual void DoTeardown (void);
-};
-
-ConversionTestCase::ConversionTestCase ()
-  : TestCase ("Check crazy time conversions")
-{
-}
-
-void ConversionTestCase::DoTeardown (void)
-{
-  TimeStepPrecision::Set (TimeStepPrecision::NS);
-}
-
-#define CHECK_CONVERSIONS(tmp)                                          \
-  do {                                                                  \
-      double val = tmp;                                                   \
-      Time t_sec = Seconds (val);                                          \
-      ASSERT_MSG_EQ (t_sec.GetSeconds (), val * 1e0, 1e0, "conv sec s");          \
-      ASSERT_MSG_EQ_INT (t_sec.GetMilliSeconds (), val * 1e3, 1e3, "conv sec ms"); \
-      ASSERT_MSG_EQ_INT (t_sec.GetMicroSeconds (), val * 1e6, 1e6, "conv sec us"); \
-      ASSERT_MSG_EQ_INT (t_sec.GetNanoSeconds (), val * 1e9, 1e9, "conv sec ns"); \
-      ASSERT_MSG_EQ_INT (t_sec.GetPicoSeconds (), val * 1e12, 1e12, "conv sec ps"); \
-      ASSERT_MSG_EQ_INT (t_sec.GetFemtoSeconds (), val * 1e15, 1e15, "conv sec fs"); \
-      uint64_t int_val = (uint64_t)val;                                  \
-      Time t_ms = MilliSeconds (int_val);                                 \
-      ASSERT_MSG_EQ (t_ms.GetSeconds (), val * 1e-3, 1e0, "conv ms s");       \
-      ASSERT_MSG_EQ_INT (t_ms.GetMilliSeconds (), val * 1e0, 1e3, "conv ms ms");     \
-      ASSERT_MSG_EQ_INT (t_ms.GetMicroSeconds (), val * 1e3, 1e6, "conv ms us"); \
-      ASSERT_MSG_EQ_INT (t_ms.GetNanoSeconds (), val * 1e6, 1e9, "conv ms ns");  \
-      ASSERT_MSG_EQ_INT (t_ms.GetPicoSeconds (), val * 1e9, 1e12, "conv ms fs"); \
-      ASSERT_MSG_EQ_INT (t_ms.GetFemtoSeconds (), val * 1e12, 1e15, "conv ms ps"); \
-      Time t_us = MicroSeconds (int_val);                                     \
-      ASSERT_MSG_EQ (t_us.GetSeconds (), val * 1e-6, 1e0, "conv us s");       \
-      ASSERT_MSG_EQ_INT (t_us.GetMilliSeconds (), val * 1e-3, 1e3, "conv us ms"); \
-      ASSERT_MSG_EQ_INT (t_us.GetMicroSeconds (), val * 1e0, 1e6, "conv us us");     \
-      ASSERT_MSG_EQ_INT (t_us.GetNanoSeconds (), val * 1e3, 1e9, "conv us ns");  \
-      ASSERT_MSG_EQ_INT (t_us.GetPicoSeconds (), val * 1e6, 1e12, "conv us ps"); \
-      ASSERT_MSG_EQ_INT (t_us.GetFemtoSeconds (), val * 1e9, 1e15, "conv us fs"); \
-      Time t_ns = NanoSeconds (int_val);                                      \
-      ASSERT_MSG_EQ (t_ns.GetSeconds (), val * 1e-9, 1e0, "conv ns s");       \
-      ASSERT_MSG_EQ_INT (t_ns.GetMilliSeconds (), val * 1e-6, 1e3, "conv ns ms"); \
-      ASSERT_MSG_EQ_INT (t_ns.GetMicroSeconds (), val * 1e-3, 1e6, "conv ns us"); \
-      ASSERT_MSG_EQ_INT (t_ns.GetNanoSeconds (), val * 1e0, 1e9, "conv ns ns");      \
-      ASSERT_MSG_EQ_INT (t_ns.GetPicoSeconds (), val * 1e3, 1e12, "conv ns ps"); \
-      ASSERT_MSG_EQ_INT (t_ns.GetFemtoSeconds (), val * 1e6, 1e15, "conv ns fs"); \
-      Time t_ps = PicoSeconds (int_val);                                      \
-      ASSERT_MSG_EQ (t_ps.GetSeconds (), val * 1e-12, 1e0, "conv ps s");      \
-      ASSERT_MSG_EQ_INT (t_ps.GetMilliSeconds (), val * 1e-9, 1e3, "conv ps ms"); \
-      ASSERT_MSG_EQ_INT (t_ps.GetMicroSeconds (), val * 1e-6, 1e6, "conv ps us"); \
-      ASSERT_MSG_EQ_INT (t_ps.GetNanoSeconds (), val * 1e-3, 1e9, "conv ps ns");  \
-      ASSERT_MSG_EQ_INT (t_ps.GetPicoSeconds (), val * 1e0, 1e12, "conv ps ps");     \
-      ASSERT_MSG_EQ_INT (t_ps.GetFemtoSeconds (), val * 1e3, 1e15, "conv ps fs"); \
-      Time t_fs = FemtoSeconds (int_val);                                     \
-      ASSERT_MSG_EQ (t_fs.GetSeconds (), val * 1e-15, 1e0, "conv fs sec");    \
-      ASSERT_MSG_EQ_INT (t_fs.GetMilliSeconds (), val * 1e-12, 1e3, "conv fs ms"); \
-      ASSERT_MSG_EQ_INT (t_fs.GetMicroSeconds (), val * 1e-9, 1e6, "conv fs us"); \
-      ASSERT_MSG_EQ_INT (t_fs.GetNanoSeconds (), val * 1e-6, 1e9, "conv fs ns");  \
-      ASSERT_MSG_EQ_INT (t_fs.GetPicoSeconds (), val * 1e-3, 1e12, "conv fs ps"); \
-      ASSERT_MSG_EQ_INT (t_fs.GetFemtoSeconds (), val * 1e0, 1e15, "conv fs fs");    \
-    } while (false)
-
-bool
-ConversionTestCase::DoRun (void)
-{
-  CHECK_CONVERSIONS (5);
-  CHECK_CONVERSIONS (0);
-  CHECK_CONVERSIONS (783);
-  CHECK_CONVERSIONS (1132);
-  // triggers overflow
-  // XXX
-  // CHECK_CONVERSIONS(3341039);
-
-  TimeStepPrecision::Set (TimeStepPrecision::US);
-  CHECK_CONVERSIONS (7);
-  CHECK_CONVERSIONS (546);
-  CHECK_CONVERSIONS (6231);
-  // triggers overflow
-  // XXX
-  // CHECK_CONVERSIONS(1234639);
-
-  TimeStepPrecision::Set (TimeStepPrecision::MS);
-  CHECK_CONVERSIONS (3);
-  CHECK_CONVERSIONS (134);
-  CHECK_CONVERSIONS (2341);
-  // triggers overflow
-  // XXX
-  // CHECK_CONVERSIONS(8956239);
-
-  TimeStepPrecision::Set (TimeStepPrecision::NS);
-  CHECK_CONVERSIONS (4);
-  CHECK_CONVERSIONS (342);
-  CHECK_CONVERSIONS (1327);
-  // triggers overflow
-  // XXX
-  // CHECK_CONVERSIONS(5439627);
-
-  TimeStepPrecision::Set (TimeStepPrecision::PS);
-  CHECK_CONVERSIONS (4);
-  CHECK_CONVERSIONS (342);
-  CHECK_CONVERSIONS (1327);
-  // triggers overflow
-  // XXX
-  // CHECK_CONVERSIONS(5439627);
-
-  TimeStepPrecision::Set (TimeStepPrecision::NS);
-  CHECK_CONVERSIONS (12);
-
-  TimeStepPrecision::Set (TimeStepPrecision::S);
-  CHECK_CONVERSIONS (7);
-
-  TimeStepPrecision::Set (TimeStepPrecision::FS);
-  CHECK_CONVERSIONS (5);
-
-  return false;
-}
-#endif
-
 class Bug863TestCase : public TestCase
 {
 public:
@@ -709,18 +205,100 @@
   return false;
 }
 
+class TimeSimpleTestCase : public TestCase
+{
+public:
+  TimeSimpleTestCase (enum Time::Unit resolution);
+private:
+  virtual bool DoRun (void);
+  virtual void DoTearDown (void);
+  enum Time::Unit m_originalResolution;
+  enum Time::Unit m_resolution;
+};
+
+TimeSimpleTestCase::TimeSimpleTestCase (enum Time::Unit resolution)
+  : TestCase ("Sanity check of common time operations"),
+    m_resolution (resolution)
+{}
+bool
+TimeSimpleTestCase::DoRun (void)
+{
+  m_originalResolution = Time::GetResolution ();
+  Time::SetResolution (m_resolution);
+  NS_TEST_ASSERT_MSG_EQ_TOL (Seconds (1.0).GetSeconds (), 1.0, TimeStep (1).GetSeconds (), 
+                             "is 1 really 1 ?");
+  NS_TEST_ASSERT_MSG_EQ_TOL (Seconds (10.0).GetSeconds (), 10.0, TimeStep (1).GetSeconds (), 
+                             "is 10 really 10 ?");
+  NS_TEST_ASSERT_MSG_EQ (MilliSeconds (1).GetMilliSeconds (), 1, 
+                         "is 1ms really 1ms ?");
+  NS_TEST_ASSERT_MSG_EQ (MicroSeconds (1).GetMicroSeconds (), 1, 
+                         "is 1us really 1us ?");
+#if 0
+  Time ns = NanoSeconds (1);
+  ns.GetNanoSeconds ();
+  NS_TEST_ASSERT_MSG_EQ (NanoSeconds (1).GetNanoSeconds (), 1, 
+                         "is 1ns really 1ns ?");
+  NS_TEST_ASSERT_MSG_EQ (PicoSeconds (1).GetPicoSeconds (), 1, 
+                         "is 1ps really 1ps ?");
+  NS_TEST_ASSERT_MSG_EQ (FemtoSeconds (1).GetFemtoSeconds (), 1, 
+                         "is 1fs really 1fs ?");
+#endif
+  return false;
+}
+
+void 
+TimeSimpleTestCase::DoTearDown (void)
+{
+  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:
   TimeTestSuite ()
     : TestSuite ("time", UNIT)
   {
-    AddTestCase (new OldTimeTestCase ());
-    AddTestCase (new OperationsTimeTestCase ());
-    AddTestCase (new TimeStepTestCase ());
-    AddTestCase (new GlobalPrecisionTestCase ());
     AddTestCase (new Bug863TestCase ());
-    // AddTestCase(new ConversionTestCase());
+    AddTestCase (new TimeSimpleTestCase (Time::US));
+    AddTestCase (new ArithTestCase ());
   }
 } g_timeTestSuite;
 
--- a/src/simulator/wscript	Sat Aug 07 14:18:16 2010 +0200
+++ b/src/simulator/wscript	Sat Aug 07 14:30:18 2010 +0200
@@ -55,6 +55,7 @@
     sim = bld.create_ns3_module('simulator', ['core'])
     sim.source = [
         'high-precision.cc',
+        'time-base.cc',
         'time.cc',
         'event-id.cc',
         'scheduler.cc',
@@ -65,6 +66,7 @@
         'ns2-calendar-scheduler.cc',
         'event-impl.cc',
         'simulator.cc',
+        'simulator-impl.cc',
         'default-simulator-impl.cc',
         'timer.cc',
         'watchdog.cc',
@@ -76,6 +78,7 @@
     headers.module = 'simulator'
     headers.source = [
         'high-precision.h',
+        'time-base.h',
         'nstime.h',
         'event-id.h',
         'event-impl.h',
@@ -105,7 +108,7 @@
     elif env['USE_HIGH_PRECISION_CAIRO']:
         sim.source.extend([
             'high-precision-cairo.cc',
-            'cairo-wideint.c',
+#            'cairo-wideint.c',
             ])
         headers.source.extend([
             'high-precision-cairo.h',