[Bug 1856] int64x64_t double conversions
authorPeter D. Barnes, Jr. <barnes26@llnl.gov>
Sun, 02 Mar 2014 01:02:23 -0800
changeset 10637 67601c471c22
parent 10636 111ac53de0e7
child 10638 aa85c4fcd5d7
[Bug 1856] int64x64_t double conversions
src/core/model/int64x64-128.cc
src/core/model/int64x64-128.h
src/core/model/int64x64-cairo.cc
src/core/model/int64x64-cairo.h
src/core/model/int64x64-double.h
src/core/model/int64x64.cc
src/core/model/int64x64.h
src/core/test/int64x64-test-suite.cc
--- a/src/core/model/int64x64-128.cc	Sun Mar 02 00:42:05 2014 -0800
+++ b/src/core/model/int64x64-128.cc	Sun Mar 02 01:02:23 2014 -0800
@@ -26,16 +26,16 @@
 }
 
 void
-int64x64_t::Mul (int64x64_t const &o)
+int64x64_t::Mul (const int64x64_t & o)
 {
   uint128_t a, b;
-  bool sign = output_sign (_v, o._v, a, b);
+  bool negative = output_sign (_v, o._v, a, b);
   uint128_t result = Umul (a, b);
-  _v = sign ? -result : result;
+  _v = negative ? -result : result;
 }
 
 uint128_t
-int64x64_t::Umul (uint128_t a, uint128_t b)
+int64x64_t::Umul (const uint128_t a, const uint128_t b)
 {
   uint128_t aL = a & HP_MASK_LO;
   uint128_t bL = b & HP_MASK_LO;
@@ -75,16 +75,16 @@
 }
 
 void
-int64x64_t::Div (int64x64_t const &o)
+int64x64_t::Div (const int64x64_t & o)
 {
   uint128_t a, b;
-  bool sign = output_sign (_v, o._v, a, b);
+  bool negative = output_sign (_v, o._v, a, b);
   int128_t result = Udiv (a, b);
-  _v = sign ? -result : result;
+  _v = negative ? -result : result;
 }
 
 uint128_t
-int64x64_t::Udiv (uint128_t a, uint128_t b)
+int64x64_t::Udiv (const uint128_t a, const uint128_t b)
 {
   
   uint128_t rem = a;
@@ -153,7 +153,7 @@
 }
 
 void 
-int64x64_t::MulByInvert (const int64x64_t &o)
+int64x64_t::MulByInvert (const int64x64_t & o)
 {
   bool negResult = _v < 0;
   uint128_t a = negResult ? -_v : _v;
@@ -161,8 +161,9 @@
 
   _v = negResult ? -result : result;
 }
+
 uint128_t
-int64x64_t::UmulByInvert (uint128_t a, uint128_t b)
+int64x64_t::UmulByInvert (const uint128_t a, const uint128_t b)
 {
   uint128_t result, ah, bh, al, bl;
   uint128_t hi, mid;
@@ -176,8 +177,9 @@
   result = hi + mid;
   return result;
 }
+
 int64x64_t 
-int64x64_t::Invert (uint64_t v)
+int64x64_t::Invert (const uint64_t v)
 {
   NS_ASSERT (v > 1);
   uint128_t a;
--- a/src/core/model/int64x64-128.h	Sun Mar 02 00:42:05 2014 -0800
+++ b/src/core/model/int64x64-128.h	Sun Mar 02 01:02:23 2014 -0800
@@ -14,32 +14,8 @@
 namespace ns3 {
 
 /**
- * \ingroup core
- * \defgroup highprec High Precision Q64.64
- *
- * Functions and class for high precision Q64.64 fixed point arithmetic.
- */
-  
-/**
- * \ingroup highprec
- * High precision numerical type, implementing Q64.64 fixed precision.
- *
- * A Q64.64 fixed precision number consists of:
- *
- *   Bits | Function
- *   ---- | --------
- *     1  | Sign bit
- *    63  | Integer portion
- *    64  | Fractional portion
- *
- * All standard arithemetic operations are supported:
- *
- *   Category    | Operators
- *   ----------- | ---------
- *   Computation | `+`, `+=`, `-`, `-=`, `*`, `*=`, `/`, `/=`
- *   Comparison  | `==`, `!=`, `<`, `<=`, `>`, `>=`
- *   Unary       | `+`, `-`, `!`
- *
+ * \internal
+ * The implementation documented here is based on native 128-bit integers.
  */
 class int64x64_t
 {
@@ -72,9 +48,9 @@
    * we expose the underlying implementation type here.
    */
   enum impl_type {
-    int128_impl = 0,  //!< Native int128_t implementation.
-    cairo_impl  = 1,  //!< cairo wideint implementation
-    ld_impl     = 2   //!< long double implementation
+    int128_impl,  //!< Native int128_t implementation.
+    cairo_impl,   //!< cairo wideint implementation
+    ld_impl,      //!< long double implementation
   };
 
   /// Type tag for this implementation.
@@ -89,27 +65,38 @@
    *
    * \param [in] value floating value to represent
    */
-  inline int64x64_t (double value)
+  inline int64x64_t (const double value)
   {
-    bool sign = value < 0;
-    value = sign ? -value : value;
-    long double hi = std::floor ((long double)value);
-    long double fr = value - hi;
-    long double lo = fr * HP_MAX_64;
-    _v = (uint128_t)hi << 64;
-    _v += (uint128_t)lo;
-    _v = sign ? -_v : _v;
+    const int64x64_t tmp ((long double)value);
+    _v = tmp._v;
   }
-  inline int64x64_t (long double value)
+  inline int64x64_t (const long double value)
   {
-    bool sign = value < 0;
-    value = sign ? -value : value;
-    long double hi = std::floor (value);
-    long double fr = value - hi;
-    long double lo = fr * HP_MAX_64;
-    _v = (uint128_t)hi << 64;
-    _v += (uint128_t)lo;
-    _v = sign ? -_v : _v;
+    const bool negative = value < 0;
+    const long double v = negative ? -value : value;
+
+    long double fhi;
+    long double flo = std::modf (v, &fhi);
+    // Add 0.5 to round, which improves the last count
+    // This breaks these tests:
+    //   TestSuite devices-mesh-dot11s-regression
+    //   TestSuite devices-mesh-flame-regression
+    //   TestSuite routing-aodv-regression
+    //   TestSuite routing-olsr-regression
+    // Setting round = 0; breaks:
+    //   TestSuite int64x64
+    const long double round = 0.5;
+    flo = flo * HP_MAX_64 + round;
+    int128_t hi = fhi;
+    const uint64_t lo = flo;
+    if (flo >= HP_MAX_64)
+      {
+	// conversion to uint64 rolled over
+	++hi;
+      }
+    _v = hi << 64;
+    _v |= lo;
+    _v = negative ? -_v : _v;
   }
   /**@}*/
 
@@ -119,32 +106,32 @@
    *
    * \param [in] v integer value to represent
    */
-  inline int64x64_t (int v)
+  inline int64x64_t (const int v)
     : _v (v)
   {
     _v <<= 64;
   }
-  inline int64x64_t (long int v)
+  inline int64x64_t (const long int v)
     : _v (v) 
   {
     _v <<= 64;
   }
-  inline int64x64_t (long long int v)
+  inline int64x64_t (const long long int v)
     : _v (v) 
   {
     _v <<= 64;
   }
-  inline int64x64_t (unsigned int v)
+  inline int64x64_t (const unsigned int v)
     : _v (v)
   {
     _v <<= 64;
   }
-  inline int64x64_t (unsigned long int v)
+  inline int64x64_t (const unsigned long int v)
     : _v (v) 
   {
     _v <<= 64;
   }
-  inline int64x64_t (unsigned long long int v)
+  inline int64x64_t (const unsigned long long int v)
     : _v (v) 
   {
     _v <<= 64;
@@ -156,13 +143,10 @@
    * \param [in] hi Integer portion.
    * \param [in] lo Fractional portion, already scaled to HP_MAX_64.
    */
-  explicit inline int64x64_t (int64_t hi, uint64_t lo)
+  explicit inline int64x64_t (const int64_t hi, const uint64_t lo)
   {
-    bool sign = hi<0;
-    _v = sign ? -hi : hi;
-    _v <<= 64;
-    _v += lo;
-    _v = sign ? -_v : _v;
+    _v = (int128_t)hi << 64;
+    _v |= lo;
   }
 
   /**
@@ -190,12 +174,13 @@
    */
   inline double GetDouble (void) const
   {
-    bool sign = _v < 0;
-    uint128_t value = sign ? -_v : _v;
-    long double flo = (value & HP_MASK_LO) / HP_MAX_64;
-    long double retval = value >> 64;
+    const bool negative = _v < 0;
+    const uint128_t value = negative ? -_v : _v;
+    const long double fhi = value >> 64;
+    const long double flo = (value & HP_MASK_LO) / HP_MAX_64;
+    long double retval = fhi;
     retval += flo;
-    retval = sign ? -retval : retval;
+    retval = negative ? -retval : retval;
     return retval;
   }
   /**
@@ -205,11 +190,8 @@
    */
   inline int64_t GetHigh (void) const
   {
-    bool sign = _v < 0;
-    int128_t value = sign ? -_v : _v;
-    value >>= 64;
-    int64_t retval = value;
-    return sign ? -retval : retval;
+    const int128_t retval = _v >> 64;
+    return retval;
   }
   /**
    * Get the fractional portion of this value, unscaled.
@@ -218,9 +200,7 @@
    */
   inline uint64_t GetLow (void) const
   {
-    bool sign = _v < 0;
-    int128_t value = sign ? -_v : _v;
-    uint128_t retval = value & HP_MASK_LO;
+    const uint128_t retval = _v & HP_MASK_LO;
     return retval;
   }
 
@@ -247,15 +227,13 @@
    * \param [in] v The value to compute the inverse of.
    * \return A Q0.128 representation of the inverse.
    */
-  static int64x64_t Invert (uint64_t v);
+  static int64x64_t Invert (const uint64_t v);
 
 private:
   friend bool         operator == (const int64x64_t & lhs, const int64x64_t & rhs);
 
   friend bool         operator <  (const int64x64_t & lhs, const int64x64_t & rhs);
-  friend bool         operator <= (const int64x64_t & lhs, const int64x64_t & rhs);
   friend bool         operator >  (const int64x64_t & lhs, const int64x64_t & rhs);
-  friend bool         operator >= (const int64x64_t & lhs, const int64x64_t & rhs);
   
   friend int64x64_t & operator += (      int64x64_t & lhs, const int64x64_t & rhs);
   friend int64x64_t & operator -= (      int64x64_t & lhs, const int64x64_t & rhs);
@@ -301,7 +279,7 @@
    * high and low 64 bits.  To achieve this, we carry out the multiplication
    * explicitly with 64-bit operands and 128-bit intermediate results.
    */
-  static uint128_t Umul         (uint128_t a, uint128_t b);
+  static uint128_t Umul         (const uint128_t a, const uint128_t b);
   /**
    * Unsigned division of Q64.64 values.
    *
@@ -309,7 +287,7 @@
    * \param [in] b Denominator.
    * \return The Q64.64 representation of `a / b`
    */
-  static uint128_t Udiv         (uint128_t a, uint128_t b);
+  static uint128_t Udiv         (const uint128_t a, const uint128_t b);
   /**
    * Unsigned multiplication of Q64.64 and Q0.128 values.
    *
@@ -319,14 +297,14 @@
    *
    * \see Invert
    */
-  static uint128_t UmulByInvert (uint128_t a, uint128_t b);
+  static uint128_t UmulByInvert (const uint128_t a, const uint128_t b);
 
   /**
    * Construct from an integral type.
    *
    * \param [in] v integer value to represent
    */
-  inline int64x64_t (int128_t v)
+  inline int64x64_t (const int128_t v)
     : _v (v) {}
 
   int128_t _v;  //!< The Q64.64 value.
@@ -344,14 +322,6 @@
 }
 /**
  * \ingroup highprec
- * Inequality operator
- */
-inline bool operator != (const int64x64_t & lhs, const int64x64_t & rhs)
-{
-  return !(lhs == rhs);
-}
-/**
- * \ingroup highprec
  * Less than operator
  */
 inline bool operator < (const int64x64_t & lhs, const int64x64_t & rhs)
@@ -360,28 +330,12 @@
 }
 /**
  * \ingroup highprec
- * Less or equal operator
- */
-inline bool operator <= (const int64x64_t & lhs, const int64x64_t & rhs)
-{
-  return lhs._v <= rhs._v;
-}
-/**
- * \ingroup highprec
  * Greater operator
  */
 inline bool operator > (const int64x64_t & lhs, const int64x64_t & rhs)
 {
   return lhs._v > rhs._v;
 }
-/**
- * \ingroup highprec
- * Greater or equal operator
- */
-inline bool operator >= (const int64x64_t & lhs, const int64x64_t & rhs)
-{
-  return lhs._v >= rhs._v;
-}
 
 /**
  * \ingroup highprec
--- a/src/core/model/int64x64-cairo.cc	Sun Mar 02 00:42:05 2014 -0800
+++ b/src/core/model/int64x64-cairo.cc	Sun Mar 02 01:02:23 2014 -0800
@@ -56,7 +56,7 @@
 }
 
 void
-int64x64_t::Mul (int64x64_t const &o)
+int64x64_t::Mul (const int64x64_t & o)
 {
   cairo_uint128_t a, b;
   bool sign = output_sign (_v, o._v, a, b);
@@ -65,7 +65,7 @@
 }
 
 cairo_uint128_t
-int64x64_t::Umul (cairo_uint128_t a, cairo_uint128_t b)
+int64x64_t::Umul (const cairo_uint128_t a, const cairo_uint128_t b)
 {
   cairo_uint128_t result;
   cairo_uint128_t hiPart, loPart, midPart;
@@ -101,7 +101,7 @@
 }
 
 void
-int64x64_t::Div (int64x64_t const &o)
+int64x64_t::Div (const int64x64_t & o)
 {
   cairo_uint128_t a, b;
   bool sign = output_sign (_v, o._v, a, b);
@@ -110,7 +110,7 @@
 }
 
 cairo_uint128_t
-int64x64_t::Udiv (cairo_uint128_t a, cairo_uint128_t b)
+int64x64_t::Udiv (const cairo_uint128_t a, const cairo_uint128_t b)
 {
   cairo_uint128_t den = b;
   cairo_uquorem128_t qr = _cairo_uint128_divrem (a, b);
@@ -176,7 +176,7 @@
 }
 
 void 
-int64x64_t::MulByInvert (const int64x64_t &o)
+int64x64_t::MulByInvert (const int64x64_t & o)
 {
   bool sign = _cairo_int128_negative (_v);
   cairo_uint128_t a = sign ? _cairo_int128_negate (_v) : _v;
@@ -184,8 +184,9 @@
 
   _v = sign ? _cairo_int128_negate (result) : result;
 }
+  
 cairo_uint128_t
-int64x64_t::UmulByInvert (cairo_uint128_t a, cairo_uint128_t b)
+int64x64_t::UmulByInvert (const cairo_uint128_t a, const cairo_uint128_t b)
 {
   cairo_uint128_t result;
   cairo_uint128_t hi, mid;
@@ -197,8 +198,9 @@
   result = _cairo_uint128_add (hi,mid);
   return result;
 }
+
 int64x64_t 
-int64x64_t::Invert (uint64_t v)
+int64x64_t::Invert (const uint64_t v)
 {
   NS_ASSERT (v > 1);
   cairo_uint128_t a, factor;
--- a/src/core/model/int64x64-cairo.h	Sun Mar 02 00:42:05 2014 -0800
+++ b/src/core/model/int64x64-cairo.h	Sun Mar 02 01:02:23 2014 -0800
@@ -10,32 +10,8 @@
 namespace ns3 {
 
 /**
- * \ingroup core
- * \defgroup highprec High Precision Q64.64
- *
- * Functions and class for high precision Q64.64 fixed point arithmetic.
- */
-  
-/**
- * \ingroup highprec
- * High precision numerical type, implementing Q64.64 fixed precision.
- *
- * A Q64.64 fixed precision number consists of:
- *
- *   Bits | Function
- *   ---- | --------
- *     1  | Sign bit
- *    63  | Integer portion
- *    64  | Fractional portion
- *
- * All standard arithemetic operations are supported:
- *
- *   Category    | Operators
- *   ----------- | ---------
- *   Computation | `+`, `+=`, `-`, `-=`, `*`, `*=`, `/`, `/=`
- *   Comparison  | `==`, `!=`, `<`, `<=`, `>`, `>=`
- *   Unary       | `+`, `-`, `!`
- *
+ * \internal
+ * The implementation documented here uses cairo 128-bit integers.
  */
 class int64x64_t
 {
@@ -66,9 +42,9 @@
    * we expose the underlying implementation type here.
    */
   enum impl_type {
-    int128_impl = 0,  //!< Native int128_t implementation.
-    cairo_impl  = 1,  //!< cairo wideint implementation
-    ld_impl     = 2   //!< long double implementation
+    int128_impl,  //!< Native int128_t implementation.
+    cairo_impl,   //!< cairo wideint implementation
+    ld_impl,      //!< long double implementation
   };
 
   /// Type tag for this implementation.
@@ -86,33 +62,38 @@
    *
    * \param [in] value floating value to represent
    */
-  inline int64x64_t (double value)
+  inline int64x64_t (const double value)
+  {
+    const int64x64_t tmp ((long double)value);
+    _v = tmp._v;
+  }
+  inline int64x64_t (const long double value)
   {
-    bool sign = value < 0;
-    value = sign ? -value : value;
-    long double hi = std::floor ((long double)value);
-    long double fr = value - hi;
-    long double lo = fr * HP_MAX_64;
+    const bool negative = value < 0;
+    const long double v = negative ? -value : value;
+
+    long double fhi;
+    long double flo = std::modf (v, &fhi);
+    // Add 0.5 to round, which improves the last count
+    // This breaks these tests:
+    //   TestSuite devices-mesh-dot11s-regression
+    //   TestSuite devices-mesh-flame-regression
+    //   TestSuite routing-aodv-regression
+    //   TestSuite routing-olsr-regression
+    // Setting round = 0; breaks:
+    //   TestSuite int64x64
+    const long double round = 0.5;
+    flo = flo * HP_MAX_64 + round;
+    cairo_int64_t  hi = fhi;
+    const cairo_uint64_t lo = flo;
+    if (flo >= HP_MAX_64)
+      {
+	// conversion to uint64 rolled over
+	++hi;
+      }
     _v.hi = hi;
     _v.lo = lo;
-    if (sign)
-      {
-	Negate ();
-      }
-  }
-  inline int64x64_t (long double value)
-  {
-    bool sign = value < 0;
-    value = sign ? -value : value;
-    long double hi = std::floor (value);
-    long double fr = value - hi;
-    long double lo = fr * HP_MAX_64;
-    _v.hi = hi;
-    _v.lo = lo;
-    if (sign)
-      {
-	Negate ();
-      }
+    _v = negative ? _cairo_int128_negate (_v) : _v;
   }
   /**@}*/
 
@@ -122,32 +103,32 @@
    *
    * \param [in] v integer value to represent
    */
-  inline int64x64_t (int v)
+  inline int64x64_t (const int v)
   {
     _v.hi = v;
     _v.lo = 0;
   }
-  inline int64x64_t (long int v)
+  inline int64x64_t (const long int v)
   {
     _v.hi = v;
     _v.lo = 0;
   }
-  inline int64x64_t (long long int v)
+  inline int64x64_t (const long long int v)
   {
     _v.hi = v;
     _v.lo = 0;
   }
-  inline int64x64_t (unsigned int v)
+  inline int64x64_t (const unsigned int v)
   {
     _v.hi = v;
     _v.lo = 0;
   }
-  inline int64x64_t (unsigned long int v)
+  inline int64x64_t (const unsigned long int v)
   {
     _v.hi = v;
     _v.lo = 0;
   }
-  inline int64x64_t (unsigned long long int v)
+  inline int64x64_t (const unsigned long long int v)
   {
     _v.hi = v;
     _v.lo = 0;
@@ -159,7 +140,7 @@
    * \param [in] hi Integer portion.
    * \param [in] lo Fractional portion, already scaled to HP_MAX_64.
    */
-  explicit inline int64x64_t (int64_t hi, uint64_t lo)
+  explicit inline int64x64_t (const int64_t hi, const uint64_t lo)
   {
     _v.hi = hi;
     _v.lo = lo;
@@ -190,12 +171,13 @@
    */
   inline double GetDouble (void) const
   {
-    bool sign = IsNegative ();
-    cairo_int128_t tmp = sign ? _cairo_int128_negate (_v) : _v;
-    long double flo = tmp.lo / HP_MAX_64;
-    long double retval = tmp.hi;
+    const bool negative = _cairo_int128_negative (_v);
+    const cairo_int128_t value = negative ? _cairo_int128_negate (_v) : _v;
+    const long double fhi = value.hi;
+    const long double flo = value.lo / HP_MAX_64;
+    long double retval = fhi;
     retval += flo;
-    retval = sign ? -retval : retval;
+    retval = negative ? -retval : retval;
     return retval;
   }
   /**
@@ -240,15 +222,13 @@
    * \param [in] v The value to compute the inverse of.
    * \return A Q0.128 representation of the inverse.
    */
-  static int64x64_t Invert (uint64_t v);
+  static int64x64_t Invert (const uint64_t v);
 
 private:
   friend bool         operator == (const int64x64_t & lhs, const int64x64_t & rhs);
 
   friend bool         operator <  (const int64x64_t & lhs, const int64x64_t & rhs);
-  friend bool         operator <= (const int64x64_t & lhs, const int64x64_t & rhs);
   friend bool         operator >  (const int64x64_t & lhs, const int64x64_t & rhs);
-  friend bool         operator >= (const int64x64_t & lhs, const int64x64_t & rhs);
   
   friend int64x64_t & operator += (      int64x64_t & lhs, const int64x64_t & rhs);
   friend int64x64_t & operator -= (      int64x64_t & lhs, const int64x64_t & rhs);
@@ -294,7 +274,7 @@
    * high and low 64 bits.  To achieve this, we carry out the multiplication
    * explicitly with 64-bit operands and 128-bit intermediate results.
    */
-  static cairo_uint128_t Umul         (cairo_uint128_t a, cairo_uint128_t b);
+  static cairo_uint128_t Umul (const cairo_uint128_t a, const cairo_uint128_t b);
   /**
    * Unsigned division of Q64.64 values.
    *
@@ -302,7 +282,7 @@
    * \param [in] b Denominator.
    * \return The Q64.64 representation of `a / b`
    */
-  static cairo_uint128_t Udiv         (cairo_uint128_t a, cairo_uint128_t b);
+  static cairo_uint128_t Udiv (const cairo_uint128_t a, const cairo_uint128_t b);
   /**
    * Unsigned multiplication of Q64.64 and Q0.128 values.
    *
@@ -312,38 +292,7 @@
    *
    * \see Invert
    */
-  static cairo_uint128_t UmulByInvert (cairo_uint128_t a, cairo_uint128_t b);
-  /** Negative predicate. */
-  inline bool IsNegative (void) const
-  {
-    bool sign = _cairo_int128_negative (_v);;
-    return sign;
-  }
-  /** Logical negation */
-  inline void Negate (void)
-  {
-    _v.lo = ~_v.lo;
-    _v.hi = ~_v.hi;
-    if (++_v.lo == 0)
-      {
-        ++_v.hi;
-      }
-  }
-  /**
-   * Return tri-valued comparision to another value.
-   *
-   * \param [in] o The value to compare to.
-   * \return -1 if `this < o`, 0 if they are equal, and +1 if `this > o`.
-   */
-  inline int Compare (const int64x64_t & o) const
-  {
-    int status;
-    int64x64_t tmp = *this;
-    tmp -= o;
-    status = (((int64_t)(tmp)._v.hi) < 0) ? -1 :
-      (((tmp)._v.hi == 0 && (tmp)._v.lo == 0)) ? 0 : 1;
-    return status;
-  }
+  static cairo_uint128_t UmulByInvert (const cairo_uint128_t a, const cairo_uint128_t b);
 
   cairo_int128_t _v;  //!< The Q64.64 value.
 
@@ -356,15 +305,7 @@
  */
 inline bool operator == (const int64x64_t & lhs, const int64x64_t & rhs)
 {
-  return lhs._v.hi == rhs._v.hi && lhs._v.lo == rhs._v.lo;
-}
-/**
- * \ingroup highprec
- * Inequality operator
- */
-inline bool operator != (const int64x64_t & lhs, const int64x64_t & rhs)
-{
-  return !(lhs == rhs);
+  return _cairo_int128_eq (lhs._v, rhs._v);
 }
 /**
  * \ingroup highprec
@@ -372,15 +313,7 @@
  */
 inline bool operator < (const int64x64_t & lhs, const int64x64_t & rhs)
 {
-  return lhs.Compare (rhs) < 0;
-}
-/**
- * \ingroup highprec
- * Less or equal operator
- */
-inline bool operator <= (const int64x64_t & lhs, const int64x64_t & rhs)
-{
-  return lhs.Compare (rhs) <= 0;
+  return _cairo_int128_lt (lhs._v, rhs._v);
 }
 /**
  * \ingroup highprec
@@ -388,15 +321,7 @@
  */
 inline bool operator > (const int64x64_t & lhs, const int64x64_t & rhs)
 {
-  return lhs.Compare (rhs) > 0;
-}
-/**
- * \ingroup highprec
- * Greater or equal operator
- */
-inline bool operator >= (const int64x64_t & lhs, const int64x64_t & rhs)
-{
-  return lhs.Compare (rhs) >= 0;
+  return _cairo_int128_gt (lhs._v, rhs._v);
 }
 
 /**
@@ -451,7 +376,7 @@
 inline int64x64_t operator - (const int64x64_t & lhs)
 {
   int64x64_t tmp = lhs;
-  tmp.Negate ();
+  tmp._v = _cairo_int128_negate (tmp._v);
   return tmp;
 }
 /**
@@ -460,7 +385,7 @@
  */
 inline int64x64_t operator ! (const int64x64_t & lhs)
 {
-  return (lhs._v.hi == 0 && lhs._v.lo == 0) ? int64x64_t (1, 0) : int64x64_t ();
+  return (lhs == int64x64_t ()) ? int64x64_t (1, 0) : int64x64_t ();
 }
 
 
--- a/src/core/model/int64x64-double.h	Sun Mar 02 00:42:05 2014 -0800
+++ b/src/core/model/int64x64-double.h	Sun Mar 02 01:02:23 2014 -0800
@@ -9,32 +9,8 @@
 namespace ns3 {
 
 /**
- * \ingroup core
- * \defgroup highprec High Precision Q64.64
- *
- * Functions and class for high precision Q64.64 fixed point arithmetic.
- */
-  
-/**
- * \ingroup highprec
- * High precision numerical type, implementing Q64.64 fixed precision.
- *
- * A Q64.64 fixed precision number consists of:
- *
- *   Bits | Function
- *   ---- | --------
- *     1  | Sign bit
- *    63  | Integer portion
- *    64  | Fractional portion
- *
- * All standard arithemetic operations are supported:
- *
- *   Category    | Operators
- *   ----------- | ---------
- *   Computation | `+`, `+=`, `-`, `-=`, `*`, `*=`, `/`, `/=`
- *   Comparison  | `==`, `!=`, `<`, `<=`, `>`, `>=`
- *   Unary       | `+`, `-`, `!`
- *
+ * \internal
+ * The implementation documented here uses native long double.
  */
 class int64x64_t
 {
@@ -63,9 +39,9 @@
    * we expose the underlying implementation type here.
    */
   enum impl_type {
-    int128_impl = 0,  //!< Native int128_t implementation.
-    cairo_impl  = 1,  //!< cairo wideint implementation
-    ld_impl     = 2   //!< long double implementation
+    int128_impl,  //!< Native int128_t implementation.
+    cairo_impl,   //!< cairo wideint implementation
+    ld_impl,      //!< long double implementation
   };
 
   /// Type tag for this implementation.
@@ -113,7 +89,12 @@
    */
   explicit inline int64x64_t (int64_t hi, uint64_t lo)
   {
-    _v = (long double)hi + (long double)lo / HP_MAX_64;
+    const bool negative = hi < 0;
+    const long double fhi = negative ? -hi : hi;
+    const long double flo = lo / HP_MAX_64;
+    _v = negative ? - fhi : fhi;
+    _v += flo;
+    // _v = negative ? -_v : _v;
   }
 
   /**
@@ -143,6 +124,48 @@
   {
     return (double)_v;
   }
+private:
+  /**
+   * Get the high and low portions of this value.
+   *
+   * \return a pair of the high and low words
+   */
+  std::pair<int64_t, uint64_t> GetHighLow (void) const
+    {
+    const bool negative = _v < 0;
+    const long double v = negative ? -_v : _v;
+
+    long double fhi;
+    long double flo = std::modf (v, &fhi);
+    // Add 0.5 to round, which improves the last count
+    // This breaks these tests:
+    //   TestSuite devices-mesh-dot11s-regression
+    //   TestSuite devices-mesh-flame-regression
+    //   TestSuite routing-aodv-regression
+    //   TestSuite routing-olsr-regression
+    // Setting round = 0; breaks:
+    //   TestSuite int64x64
+    const long double round = 0.5;
+    flo = flo * HP_MAX_64 + round;
+    int64_t  hi = fhi;
+    uint64_t lo = flo;
+    if (flo >= HP_MAX_64)
+      {
+	// conversion to uint64 rolled over
+	++hi;
+      }
+    if (negative)
+      {
+	lo = ~lo;
+	hi = ~hi;
+	if (++lo == 0)
+	  {
+	    ++hi;
+	  }
+      }
+    return std::make_pair (hi, lo);
+    }
+public:
   /**
    * Get the integer portion.
    *
@@ -150,8 +173,50 @@
    */
   inline int64_t GetHigh (void) const
   {
-    return (int64_t)std::floor (_v);
+    return GetHighLow ().first;
   }
+private:
+  /**
+   * Get the high and low portions of this value.
+   *
+   * \return a pair of the high and low words
+   */
+  std::pair<int64_t, uint64_t> GetHighLow (void) const
+    {
+    const bool negative = _v < 0;
+    const long double v = negative ? -_v : _v;
+
+    long double fhi;
+    long double flo = std::modf (v, &fhi);
+    // Add 0.5 to round, which improves the last count
+    // This breaks these tests:
+    //   TestSuite devices-mesh-dot11s-regression
+    //   TestSuite devices-mesh-flame-regression
+    //   TestSuite routing-aodv-regression
+    //   TestSuite routing-olsr-regression
+    // Setting round = 0; breaks:
+    //   TestSuite int64x64
+    const long double round = 0.5;
+    flo = flo * HP_MAX_64 + round;
+    int64_t  hi = fhi;
+    uint64_t lo = flo;
+    if (flo >= HP_MAX_64)
+      {
+	// conversion to uint64 rolled over
+	++hi;
+      }
+    if (negative)
+      {
+	lo = ~lo;
+	hi = ~hi;
+	if (++lo == 0)
+	  {
+	    ++hi;
+	  }
+      }
+    return std::make_pair (hi, lo);
+    }
+public:
   /**
    * Get the fractional portion of this value, unscaled.
    *
@@ -159,10 +224,7 @@
    */
   inline uint64_t GetLow (void) const
   {
-    long double frac = _v - std::floor (_v);
-    frac = frac * HP_MASK_LO + 0.5L;
-    uint64_t low = (uint64_t)frac;
-    return low;
+    return GetHighLow ().second;
   }
 
   /**
@@ -195,9 +257,7 @@
   friend bool         operator == (const int64x64_t & lhs, const int64x64_t & rhs);
 
   friend bool         operator <  (const int64x64_t & lhs, const int64x64_t & rhs);
-  friend bool         operator <= (const int64x64_t & lhs, const int64x64_t & rhs);
   friend bool         operator >  (const int64x64_t & lhs, const int64x64_t & rhs);
-  friend bool         operator >= (const int64x64_t & lhs, const int64x64_t & rhs);
   
   friend int64x64_t & operator += (      int64x64_t & lhs, const int64x64_t & rhs);
   friend int64x64_t & operator -= (      int64x64_t & lhs, const int64x64_t & rhs);
@@ -222,14 +282,6 @@
 }
 /**
  * \ingroup highprec
- * Inequality operator
- */
-inline bool operator != (const int64x64_t & lhs, const int64x64_t & rhs)
-{
-  return !(lhs == rhs);
-}
-/**
- * \ingroup highprec
  * Less than operator
  */
 inline bool operator < (const int64x64_t & lhs, const int64x64_t & rhs)
@@ -238,28 +290,12 @@
 }
 /**
  * \ingroup highprec
- * Less or equal operator
- */
-inline bool operator <= (const int64x64_t & lhs, const int64x64_t & rhs)
-{
-  return lhs._v <= rhs._v;
-}
-/**
- * \ingroup highprec
  * Greater operator
  */
 inline bool operator > (const int64x64_t & lhs, const int64x64_t & rhs)
 {
   return lhs._v > rhs._v;
 }
-/**
- * \ingroup highprec
- * Greater or equal operator
- */
-inline bool operator >= (const int64x64_t & lhs, const int64x64_t & rhs)
-{
-  return lhs._v >= rhs._v;
-}
 
 /**
  * \ingroup highprec
--- a/src/core/model/int64x64.cc	Sun Mar 02 00:42:05 2014 -0800
+++ b/src/core/model/int64x64.cc	Sun Mar 02 01:02:23 2014 -0800
@@ -14,33 +14,40 @@
 
 namespace ns3 {
 
+/**
+ * \internal
+ * This algorithm is exact to the precision requested, up to the full
+ * 64 decimal digits required to exactly represent a 64-bit fraction.
+ *
+ * Proper rounding turns out to be surprisingly hard.
+ * In `y.xxxx5|6`, where the `|` marks follows the last output digit,
+ * rounding the `5|6` to `6|` is straightforward.  However,
+ * rounding `y.xxx99|6` should result in `y.xx100|`.  Notice the
+ * effect of rounding percolates to higher digits.
+ * We accumulate the output digits in a string, then carry out
+ * the rounding in the string directly.
+ */
 std::ostream &operator << (std::ostream &os, const int64x64_t &value)
 {
-  int64_t hi = value.GetHigh ();
+  const bool negative = (value < 0);
+  const int64x64_t absVal = (negative ? -value : value);
+  
+  int64_t hi = absVal.GetHigh ();
 
   // Save stream format flags
+  const std::streamsize precision = os.precision ();
   std::ios_base::fmtflags ff = os.flags ();
-  os << std::setw (1);
+  const bool floatfield = os.flags () & std::ios_base::floatfield;
+  os << std::setw (1) << std::noshowpos;
+  
+  os << std::right << (negative ? "-" : "+");
 
-  { /// \internal
-    /// See \bugid{1737}:  gcc libstc++ 4.2 bug
-    if (hi == 0)
-      { 
-	os << '+';
-      }
-    else
-      {
-	os << std::showpos;
-      }
-  }
-  
-  os << std::right << hi << ".";
+  std::ostringstream oss;
+  oss << hi << ".";  // collect the digits here so we can round properly
 
-  os << std::noshowpos;
 
-  int64x64_t low(0, value.GetLow ());
+  int64x64_t low(0, absVal.GetLow ());
   int places = 0;    // Number of decimal places printed so far
-  const bool floatfield = os.flags () & std::ios_base::floatfield;
   bool more = true;  // Should we print more digits?
 
 #define HEXHILOW(hi, lo) \
@@ -51,25 +58,28 @@
 
   
   NS_LOG_LOGIC (std::endl
-		<< "  [.] " << " " << HEXHILOW (hi, low.GetLow ()) 
-		<< ": " << hi << ".");
+		<< (floatfield ? " f" : "  ")
+		<< "[" << precision << "] " << hi << ". "
+		<< HEXHILOW (hi, low.GetLow ())
+		);
 
+  int64_t digit;
   do 
     {
       low *= 10;
-      int64_t digit = low.GetHigh ();
+      digit = low.GetHigh ();
       NS_ASSERT_MSG ( (0 <= digit) && (digit <= 9),
 		      "digit " << digit << " out of range [0,9] "
 		      << " streaming out "
 		      << HEXHILOW (value.GetHigh (), value.GetLow ()) );
       low -= digit;
 
-      os << std::setw (1) << digit;
+      oss << std::setw (1) << digit;
 
       ++places;
       if (floatfield)
 	{
-	  more = places < os.precision ();
+	  more = places < precision;
 	}
       else  // default
 	{
@@ -81,10 +91,46 @@
 		    << (floatfield ? "f" : " ")
 		    << "[" << places << "] " << digit
 		    << HEXHILOW (low.GetHigh (), low.GetLow ())
-		    << std::dec << std::setfill (' ' ) << std::left << ")" );
+		    << std::dec << std::setfill (' ' ) << std::left);
 
     } while (more);
 
+  // Check if we need to round the last printed digit,
+  // based on the first unprinted digit
+  std::string digits = oss.str ();
+  low *= 10;
+  int64_t nextDigit = low.GetHigh ();
+  if ( (nextDigit > 5) || ((nextDigit == 5) && (digit % 2 == 1)) )
+    {
+      // Walk backwards with the carry
+      bool carry = true;
+      for (std::string::reverse_iterator rit = digits.rbegin ();
+	   rit != digits.rend ();
+	   ++rit)
+	{
+	  if (*rit == '.')  // Skip over the decimal point
+	    {
+	      continue ;
+	    }
+	  
+	  ++(*rit);         // Add the carry
+	  if (*rit <= '9')  // Relies on character order...
+	    {
+	      carry = false;
+	      break ;       // Carry complete
+	    }
+	  else
+	    {
+	      *rit = '0';     // Continue carry to next higher digit
+	    }
+	}
+      if (carry)            // If we still have a carry...
+	{
+	  digits.insert (digits.begin (), '1');
+	}
+    }
+  os << digits;
+  
   os.flags (ff);  // Restore stream flags
   return os;
 }
@@ -96,7 +142,7 @@
   while (*buf != 0)
     {
       retval *= 10;
-      retval += *buf - 0x30;
+      retval += *buf - '0';
       buf++;
     }
   return retval;
@@ -104,14 +150,14 @@
 
 static uint64_t ReadLoDigits (std::string str)
 {
-  int64x64_t low (0, 0);
-  const int64x64_t round (0, 5);
+  int64x64_t low;
+  const int64x64_t round (0, 5);  // Round last place in division
 
-  for (std::string::const_reverse_iterator rchar = str.rbegin ();
-       rchar != str.rend ();
-       ++rchar)
+  for (std::string::const_reverse_iterator rit = str.rbegin ();
+       rit != str.rend ();
+       ++rit)
     {
-      int digit = *rchar - '0';
+      int digit = *rit - '0';
       NS_ASSERT_MSG ( (0 <= digit) && (digit <= 9),
 		      "digit " << digit << " out of range [0,9]"
 		      << " streaming in low digits \"" << str << "\"");
@@ -160,13 +206,20 @@
       hi = ReadHiDigits (str.substr (cur, next-cur));
       lo = ReadLoDigits (str.substr (next+1, str.size ()-(next+1)));
     }
-  else
+  else if (cur != std::string::npos)
     {
       hi = ReadHiDigits (str.substr (cur, str.size ()-cur));
       lo = 0;
     }
-  hi = negative ? -hi : hi;
+  else
+    {
+      hi = 0;
+      lo = 0;
+    }
+  
   value = int64x64_t (hi, lo);
+  value = negative ? -value : value;
+
   return is;
 }
 
--- a/src/core/model/int64x64.h	Sun Mar 02 00:42:05 2014 -0800
+++ b/src/core/model/int64x64.h	Sun Mar 02 01:02:23 2014 -0800
@@ -20,6 +20,74 @@
 namespace ns3 {
 
 /**
+ * \ingroup core
+ * \defgroup highprec High Precision Q64.64
+ *
+ * Functions and class for high precision Q64.64 fixed point arithmetic.
+ */
+  
+/**
+ * \ingroup highprec
+ * \class int64x64_t
+ * 
+ * High precision numerical type, implementing Q64.64 fixed precision.
+ *
+ * A Q64.64 fixed precision number consists of:
+ *
+ *   Bits | Function
+ *   ---- | --------
+ *     1  | Sign bit
+ *    63  | Integer portion
+ *    64  | Fractional portion
+ *
+ * The `high` word consists of the sign bit and integer value;
+ * the `low` word is the fractional part, unscaled.
+ *
+ * All standard arithmetic operations are supported:
+ *
+ *   Category    | Operators
+ *   ----------- | ---------
+ *   Computation | `+`, `+=`, `-`, `-=`, `*`, `*=`, `/`, `/=`
+ *   Comparison  | `==`, `!=`, `<`, `<=`, `>`, `>=`
+ *   Unary       | `+`, `-`, `!`
+ */
+
+
+/**
+ * \ingroup core
+ * \defgroup highprec High Precision Q64.64
+ *
+ * Functions and class for high precision Q64.64 fixed point arithmetic.
+ */
+  
+/**
+ * \ingroup highprec
+ * \class int64x64_t
+ * 
+ * High precision numerical type, implementing Q64.64 fixed precision.
+ *
+ * A Q64.64 fixed precision number consists of:
+ *
+ *   Bits | Function
+ *   ---- | --------
+ *     1  | Sign bit
+ *    63  | Integer portion
+ *    64  | Fractional portion
+ *
+ * The `high` word consists of the sign bit and integer value;
+ * the `low` word is the fractional part, unscaled.
+ *
+ * All standard arithmetic operations are supported:
+ *
+ *   Category    | Operators
+ *   ----------- | ---------
+ *   Computation | `+`, `+=`, `-`, `-=`, `*`, `*=`, `/`, `/=`
+ *   Comparison  | `==`, `!=`, `<`, `<=`, `>`, `>=`
+ *   Unary       | `+`, `-`, `!`
+ */
+
+
+/**
  * \ingroup highprec
  * Addition operator.
  */
@@ -63,7 +131,30 @@
   tmp /= rhs;
   return tmp;
 }
-
+/**
+ * \ingroup highprec
+ * Inequality operator
+ */
+inline bool operator != (const int64x64_t & lhs, const int64x64_t & rhs)
+{
+  return !(lhs == rhs);
+}
+/**
+ * \ingroup highprec
+ * Less or equal operator
+ */
+inline bool operator <= (const int64x64_t & lhs, const int64x64_t & rhs)
+{
+  return !(lhs > rhs);
+}
+/**
+ * \ingroup highprec
+ * Greater or equal operator
+ */
+inline bool operator >= (const int64x64_t & lhs, const int64x64_t & rhs)
+{
+  return !(lhs < rhs);
+}
 /**
  * \ingroup highprec
  * Output streamer for int64x64_t
--- a/src/core/test/int64x64-test-suite.cc	Sun Mar 02 00:42:05 2014 -0800
+++ b/src/core/test/int64x64-test-suite.cc	Sun Mar 02 01:02:23 2014 -0800
@@ -1,15 +1,26 @@
 #include "ns3/int64x64.h"
 #include "ns3/test.h"
 
+#include <cmath>    // fabs
 #include <iomanip>
+#include <limits>   // numeric_limits<>::epsilon ()
 
 using namespace ns3;
 
+namespace ns3 {
+
+  namespace int64x64 {
+
+    namespace test {
+  
 /**
+ * \class ns3::int64x64::Int64x64TestSuite
  * \internal
  *
  * Some of these tests are a little unusual for ns-3 in that they
- * are sensitive to implementation, specifically the double implementation.
+ * are sensitive to implementation, specifically the resolution
+ * of the double and long double implementations.
+ * 
  * To handle this, where needed we define a tolerance to use in the
  * test comparisions.  If you need to increase the tolerance,
  * please append the system and compiler version.  For example:
@@ -21,60 +32,118 @@
  *   tolerance = 3;
  * \endcode
  */
+
+
+class Printer
+{
+public:
+  Printer (const int64_t high, const uint64_t low)
+    : m_haveInt (false),
+      m_value (0),
+      m_high (high),
+      m_low (low)
+  { }
+
+  Printer (const int64x64_t value)
+    : m_haveInt (true),
+      m_value (value),
+      m_high (value.GetHigh ()),
+      m_low (value.GetLow ())
+  { }
+
+private:
+  friend std::ostream & operator << (std::ostream & os, const Printer & p);
+
+  bool       m_haveInt;
+  int64x64_t m_value;
+  int64_t    m_high;
+  uint64_t   m_low;
+};
+
+std::ostream & operator << (std::ostream & os, const Printer & p)
+{
+  if (p.m_haveInt)
+    {
+      os << std::fixed << std::setprecision (22)
+	 << p.m_value;
+
+    }
+  
+  os << std::hex  << std::setfill ('0')
+     << " (0x" << std::setw (16) << p.m_high
+     << " 0x"  << std::setw (16) << p.m_low  << ")"
+     << std::dec  << std::setfill (' ');
+  return os;
+}
+
+	      
 class Int64x64HiLoTestCase : public TestCase
 {
 public:
   Int64x64HiLoTestCase ();
   virtual void DoRun (void);
-  void Check (const int64_t hi, const uint64_t lo,
-	      const int64_t loTolerance = 0);
+  void Check (const int64_t hi, const uint64_t lo);
 };
 
-void 
-Int64x64HiLoTestCase::Check (const int64_t hi,
-			     const uint64_t lo,
-			     const int64_t loTolerance /* = 0 */)
-{
-  int64x64_t tmp = int64x64_t (hi,lo);
-
-  std::cout << GetParent ()->GetName () << " Check "
-	    << std::hex  << std::setfill ('0')
-	    << "hi: 0x"  << std::setw (16) << hi
-	    << " lo: 0x" << std::setw (16) << lo
-	    << std::dec  << std::setfill (' ')
-	    << " int64x64: " << tmp
-	    << std::endl;
-
-  NS_TEST_EXPECT_MSG_EQ (tmp.GetHigh (), hi,
-			 "High part does not match for hi:" << hi
-			 << " lo: " << lo);
-  NS_TEST_EXPECT_MSG_EQ_TOL ((int64_t)tmp.GetLow (), (int64_t)lo, loTolerance,
-			     "Low part does not match for hi: " << hi
-			     << " lo: " << lo);
-}
-
 Int64x64HiLoTestCase::Int64x64HiLoTestCase ()
   : TestCase ("Manipulate the high and low part of every number")
 {
 }
-void
-Int64x64HiLoTestCase::DoRun (void)
+
+void 
+Int64x64HiLoTestCase::Check (const int64_t hi, const uint64_t lo)
 {
-  std::cout << std::endl;
-  std::cout << GetParent ()->GetName () << ": " << GetName () << ":"
-	    << std::endl;
-
-  int64_t tolerance = 0;
+  uint64_t tolerance = 0;
   if (int64x64_t::implementation == int64x64_t::ld_impl)
     {
       // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
       tolerance = 1;
     }
-      
-  Check (1,  0);
-  Check (1,  1, tolerance);
+
+  int64x64_t value = int64x64_t (hi,lo);
+  uint64_t vLow = value.GetLow ();
+  bool pass = ( (value.GetHigh () == hi)
+		&& ( (Max (vLow, lo) - Min (vLow, lo)) <= tolerance)
+		);
+
+  std::cout << GetParent ()->GetName () << " Check: "
+	    << (pass ? "pass " : "FAIL ")
+	    << Printer (value) << " from" << Printer (hi, lo)
+	    << std::endl;
+
+  NS_TEST_EXPECT_MSG_EQ (value.GetHigh (), hi,
+			 "High part does not match for hi:" << hi
+			 << " lo: " << lo);
+  NS_TEST_EXPECT_MSG_EQ_TOL ((int64_t)vLow, (int64_t)lo, (int64_t)tolerance,
+			     "Low part does not match for hi: " << hi
+			     << " lo: " << lo);
+}
+
+void
+Int64x64HiLoTestCase::DoRun (void)
+{
+  std::cout << std::endl;
+  std::cout << GetParent ()->GetName () << " Check: " << GetName ()
+	    << std::endl;
+
+  uint64_t low = 1;
+  if (int64x64_t::implementation == int64x64_t::ld_impl)
+    {
+      // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
+      low = 2 * HP_MAX_64 * std::numeric_limits<long double>::epsilon ();
+    }
+
+  Check ( 0, 0);
+  Check ( 0, low);
+  Check ( 0, 0xffffffffffffffffULL - low);
+  
+  Check ( 1, 0);
+  Check ( 1, low);
+  Check ( 1, 0xffffffffffffffffULL - low);
+  
   Check (-1, 0);
-  Check (-1, 1);
+  Check (-1, low);
+  Check (-1, 0xffffffffffffffffULL - low);
 }
 
 
@@ -85,7 +154,7 @@
   virtual void DoRun (void);
   void Check (const std::string & str,
 	      const int64_t hi, const uint64_t lo,
-	      const int64_t loTolerance = 0);
+	      const int64_t tolerance = 0);
 };
 Int64x64InputTestCase::Int64x64InputTestCase ()
   : TestCase ("Parse int64x64_t numbers as strings")
@@ -94,29 +163,31 @@
 void 
 Int64x64InputTestCase::Check (const std::string & str,
 			      const int64_t hi, const uint64_t lo,
-			      const int64_t loTolerance /* = 0 */)
+			      const int64_t tolerance /* = 0 */)
 			      
 {
   std::istringstream iss;
   iss.str (str);
-  int64x64_t hp;
-  iss >> hp;
+  int64x64_t value;
+  iss >> value;
 
   std::string input = "\"" + str + "\"";
+  uint64_t vLow = value.GetLow ();
+  bool pass = ( (value.GetHigh () == hi) &&
+		( Max (vLow, lo) - Min (vLow, lo) <= tolerance)
+		);
 
   std::cout << GetParent ()->GetName () << " Input: "
+	    << (pass ? "pass " : "FAIL ")
 	    << std::left << std::setw (28) << input << std::right
-	    << std::hex  << std::setfill ('0')
-	    << " hi: 0x" << std::setw (16) << hp.GetHigh ()
-	    << " lo: 0x" << std::setw (16) << hp.GetLow ()
-	    << std::dec  << std::setfill (' ')
-	    << " expected: " << hi << " " << lo << " +/- " << loTolerance
+	    << Printer (value) 
+	    << " expected: " << Printer (hi, lo) << " +/- " << tolerance
 	    << std::endl;
 
-  NS_TEST_EXPECT_MSG_EQ (hp.GetHigh (), hi,
+  NS_TEST_EXPECT_MSG_EQ (value.GetHigh (), hi,
 			 "High parts do not match for input string \""
 			 << str << "\"");
-  NS_TEST_EXPECT_MSG_EQ_TOL ((int64_t)hp.GetLow (), (int64_t)lo, loTolerance,
+  NS_TEST_EXPECT_MSG_EQ_TOL ((int64_t)value.GetLow (), (int64_t)lo, tolerance,
 			     "Low parts do not match for input string \""
 			     << str << "\"");
 }
@@ -124,7 +195,7 @@
 Int64x64InputTestCase::DoRun (void)
 {
   std::cout << std::endl;
-  std::cout << GetParent ()->GetName () << ": " << GetName () << ":"
+  std::cout << GetParent ()->GetName () << " Input: " << GetName ()
 	    << std::endl;
 
   int64_t tolerance = 0;
@@ -147,9 +218,10 @@
   Check ("-1.0", -1, 0, tolerance);
   Check ("-1.0000", -1, 0, tolerance);
   Check (" 1.000000000000000000054",  1, 1, tolerance);
-  Check ("-1.000000000000000000054", -1, 1, tolerance);
+  Check ("-1.000000000000000000054", -2, -1, tolerance);
 }
 
+
 class Int64x64InputOutputTestCase : public TestCase
 {
 public:
@@ -166,36 +238,52 @@
 Int64x64InputOutputTestCase::Check (const std::string & str,
 				    const int64_t tolerance /* = 0 */)
 {
-  std::istringstream iss;
-  iss.str (str);
+  std::stringstream iss (str);
+  int64x64_t expect;
+  iss >> expect;
+
+  std::stringstream oss;
+  oss << std::scientific << std::setprecision (21) << expect;
   int64x64_t value;
-  iss >> value;
-  std::ostringstream oss;
-  oss << std::scientific << std::setprecision (21) << value;
+  oss >> value;
+
+  bool pass = Abs (value - expect) <= int64x64_t (0, tolerance + 1);
 
   std::string input  = "\"" + str + "\"";
   std::string output = "\"" + oss.str () + "\"";
 
-  std::cout << GetParent ()->GetName () << " InputOutput: "
-	    << " in: "  << std::left << std::setw (28) << input  << std::right
-	    << " out: " << std::left << std::setw (28) << output << std::right
-	    << std::endl;
-
-  if (tolerance == 0)
+  if (pass)
     {
-      NS_TEST_EXPECT_MSG_EQ (oss.str (), str,
-			     "Converted string does not match expected string");
+      std::cout << GetParent ()->GetName () << " InputOutput: "
+		<< (pass ? "pass " : "FAIL ")
+		<< " in:  " << std::left << std::setw (28) << input
+		<< " out: " << std::left << std::setw (28) << output
+		<< std::right
+		<< std::endl;
     }
   else
     {
-      // No obvious way to implement a tolerance
-    }
+      std::cout << GetParent ()->GetName () << " InputOutput: "
+		<< (pass ? "pass " : "FAIL ")
+		<< " in:  " << std::left << std::setw (28) << input
+		<< std::right << Printer (expect)
+		<< std::endl;
+      std::cout << GetParent ()->GetName ()
+		<< std::setw (19) << " "
+		<< " out: " << std::left << std::setw (28) << output
+		<< std::right << Printer (value)
+		<< std::endl;
+    }      
+
+  NS_TEST_EXPECT_MSG_EQ_TOL (value, expect, int64x64_t (0, tolerance),
+			     "Converted string does not match expected string");
 }
+
 void
 Int64x64InputOutputTestCase::DoRun (void)
 {
   std::cout << std::endl;
-  std::cout << GetParent ()->GetName () << ": " << GetName () << ":"
+  std::cout << GetParent ()->GetName () << " InputOutput: " << GetName ()
 	    << std::endl;
 
   int64_t tolerance = 0;
@@ -222,9 +310,9 @@
   Int64x64ArithmeticTestCase ();
   virtual void DoRun (void);
   void Check (const int        test,
-	      const int64x64_t value, const int64x64_t expected);
+	      const int64x64_t value, const int64x64_t expect);
   void Check (const int        test,
-	      const int64x64_t value, const int64x64_t expected,
+	      const int64x64_t value, const int64x64_t expect,
 	      const int64x64_t tolerance);
 };
 
@@ -235,36 +323,40 @@
 void
 Int64x64ArithmeticTestCase::Check (const int test,
 				   const int64x64_t value,
-				   const int64x64_t expected)
+				   const int64x64_t expect)
 {
   int64x64_t zero (0,0);
-  Check (test, value, expected, zero);
+  Check (test, value, expect, zero);
 }
 void
 Int64x64ArithmeticTestCase::Check (const int test,
 				   const int64x64_t value,
-				   const int64x64_t expected,
+				   const int64x64_t expect,
 				   const int64x64_t tolerance)
 {
+  bool pass = Abs (value - expect) <= tolerance;
+  
   std::cout << GetParent ()->GetName () << " Arithmetic: "
-	    << test << ": " << value << " ?= " << expected
+	    << (pass ? "pass " : "FAIL ")
+	    << test << ": " << value << " == " << expect
 	    << " (+/- " << tolerance << ")"
 	    << std::endl;
   
-  NS_TEST_ASSERT_MSG_EQ_TOL ( value, expected, tolerance,
+  NS_TEST_ASSERT_MSG_EQ_TOL ( value, expect, tolerance,
 			      "Arithmetic failure in test case " << test);
 }
 
 void
 Int64x64ArithmeticTestCase::DoRun (void)
 {
+  const int64x64_t tol1 (0, 1);
   const int64x64_t zero (0, 0);
   const int64x64_t one  (1, 0);
   const int64x64_t two  (2, 0);
   const int64x64_t thre (3, 0);
 
   std::cout << std::endl;
-  std::cout << GetParent ()->GetName () << ": " << GetName () << ":"
+  std::cout << GetParent ()->GetName () << " Arithmetic: " << GetName ()
 	    << std::endl;
   
   Check ( 0,   zero  -   zero ,   zero  );
@@ -290,67 +382,71 @@
   Check (18,   one   * (-one ),  -one   );
   Check (19, (-one ) * (-one ),   one   );
   
-  Check (20, (two  * thre ) / thre , two  );
+  Check (20,  (two  * thre ) / thre , two  );
 
   const int64x64_t frac  = int64x64_t (0, 0xc000000000000000ULL);  // 0.75
   const int64x64_t fplf2 = frac + frac * frac;  // 1.3125
-  NS_TEST_ASSERT_MSG_EQ (frac,  0.75,   "Arithmetic failure fractional part");
-  NS_TEST_ASSERT_MSG_EQ (fplf2, 1.3125, "Arithmetic failure fplf2");
+  
+  Check (21,   frac,              0.75);
+  Check (22,   fplf2,             1.3125);
   
   const int64x64_t zerof = zero + frac;
-  NS_TEST_ASSERT_MSG_EQ (zerof, frac,   "Arithmetic failure adding fractional part");
   const int64x64_t onef  = one  + frac;
   const int64x64_t twof  = two  + frac;
   const int64x64_t thref = thre + frac;
+
+  Check (23,   zerof,             frac);
   
-  Check (21,   zerof -   zerof,   zero );
-  Check (22,   zerof -   onef,   -one  );
-  Check (23,   onef  -   onef,    zero );
-  Check (24,   onef  -   twof,   -one  );
-  Check (25,   onef  - (-onef),   twof  + frac  );
-  Check (26, (-onef) - (-twof),   one  );
-  Check (27, (-onef) -   twof,   -thref - frac  );
+  
+  Check (24,   zerof -   zerof,   zero );
+  Check (25,   zerof -   onef,   -one  );
+  Check (26,   onef  -   onef,    zero );
+  Check (27,   onef  -   twof,   -one  );
+  Check (28,   onef  - (-onef),   twof  + frac  );
+  Check (29 , (-onef) - (-twof),   one  );
+  Check (30 , (-onef) -   twof,   -thref - frac  );
   
-  Check (28,   zerof +   zerof,   zerof + frac  );
-  Check (29,   zerof +   onef,    onef  + frac  );
-  Check (30,   onef  +   onef,    twof  + frac  );
-  Check (31,   onef  +   twof,    thref + frac  );
-  Check (32,   onef  + (-onef),   zero  );
-  Check (33, (-onef) + (-twof),  -thref - frac  );
-  Check (34, (-onef) +   twof,    one   );
+  Check (31,   zerof +   zerof,   zerof + frac  );
+  Check (32,   zerof +   onef,    onef  + frac  );
+  Check (33,   onef  +   onef,    twof  + frac  );
+  Check (34,   onef  +   twof,    thref + frac  );
+  Check (35,   onef  + (-onef),   zero  );
+  Check (36 , (-onef) + (-twof),  -thref - frac  );
+  Check (37, (-onef) +   twof,    one   );
   
-  Check (35,   zerof *   zerof,   frac  * frac  );
-  Check (36,   zero  *   onef,    zero  );
-  Check (37,   zerof *   one,     frac  );
+  Check (38,   zerof *   zerof,   frac  * frac  );
+  Check (39 ,   zero  *   onef,    zero  );
+  Check (40 ,   zerof *   one,     frac  );
   
-  Check (38,   zerof *   onef,    fplf2 );
-  Check (39,   zerof * (-onef),  -fplf2 );
-  Check (40,   onef  *   onef,    onef  + fplf2 );
-  Check (41,   onef  * (-onef),  -onef  - fplf2 );
-  Check (42, (-onef) * (-onef),   onef  + fplf2 );
+  Check (41,   zerof *   onef,    fplf2 );
+  Check (42,   zerof * (-onef),  -fplf2 );
+  Check (43,   onef  *   onef,    onef  + fplf2 );
+  Check (44,   onef  * (-onef),  -onef  - fplf2 );
+  Check (45, (-onef) * (-onef),   onef  + fplf2 );
   
   
   // Multiplication followed by division is exact:
-  Check (43, (two  * thre ) / thre , two  );
-  Check (44, (twof * thref) / thref, twof );
+  Check (46, (two  * thre ) / thre , two  );
+  Check (47, (twof * thref) / thref, twof );
 
   // Division followed by multiplication loses a bit or two:
-  int64x64_t tolerance (0, 3);
-  Check (45, (two  / thre)  * thre,  two , tolerance );
-  Check (46, (twof / thref) * thref, twof, tolerance );
+  Check (48, (two  / thre)  * thre,  two , 2 * tol1 );
+  Check (49, (twof / thref) * thref, twof, 3 * tol1 );
 
   // The example below shows that we really do not lose
   // much precision internally: it is almost always the
   // final conversion which loses precision.
-  Check (47, (int64x64_t (2000000000) / int64x64_t (3)) * int64x64_t (3),
+  Check (50, (int64x64_t (2000000000) / int64x64_t (3)) * int64x64_t (3),
 	      int64x64_t (1999999999, 0xfffffffffffffffeULL));
 
   // Check special values
-  Check (48,  int64x64_t (0, 0x159fa87f8aeaad21ULL) * 10,
+  Check (51,  int64x64_t (0, 0x159fa87f8aeaad21ULL) * 10,
 	           int64x64_t (0, 0xd83c94fb6d2ac34aULL));
   
 }
 
+
+
 /**
  * See \bugid{455}
  */
@@ -371,7 +467,10 @@
 Int64x64Bug455TestCase::Check (const double result, const double expect,
 			       const std::string & msg)
 {
+  bool pass = result == expect;
+  
   std::cout << GetParent ()->GetName () << " Bug 455: "
+	    << (pass ? "pass " : "FAIL ")
 	    << "res: "  << result
 	    << " exp: " << expect
 	    << ": " << msg
@@ -384,7 +483,7 @@
 Int64x64Bug455TestCase::DoRun (void)
 {
   std::cout << std::endl;
-  std::cout << GetParent ()->GetName () << ": " << GetName () << ":"
+  std::cout << GetParent ()->GetName () << " Bug 455: " << GetName ()
 	    << std::endl;
   
   int64x64_t a = int64x64_t (0.1);
@@ -408,6 +507,8 @@
   Check (a.GetDouble (), -2.5, "only second operand negative");
 }
 
+
+
 /**
  * See \bugid{863}
  */
@@ -428,7 +529,10 @@
 Int64x64Bug863TestCase::Check (const double result, const double expect,
 			       const std::string & msg)
 {
+  bool pass = result == expect;
+  
   std::cout << GetParent ()->GetName () << " Bug 863: "
+	    << (pass ? "pass " : "FAIL ")
 	    << "res: "  << result
 	    << " exp: " << expect
 	    << ": " << msg
@@ -441,7 +545,7 @@
 Int64x64Bug863TestCase::DoRun (void)
 {
   std::cout << std::endl;
-  std::cout << GetParent ()->GetName () << ": " << GetName () << ":"
+  std::cout << GetParent ()->GetName () << " Bug 863: " << GetName ()
 	    << std::endl;
   
   int64x64_t a = int64x64_t (0.9);
@@ -467,6 +571,7 @@
   Check (a.GetDouble (), 1.0, "both arguments negative");
 }
 
+
 /**
  * See \bugid{1786}
  */
@@ -490,28 +595,43 @@
 {
   int64x64_t value (0, low);
   std::ostringstream oss;
-  oss << std::scientific << std::setprecision (21) << value;
-  
-  std::cout << GetParent ()->GetName () << " Bug 1786: "
-	    << "    0x" << std::hex << std::setw (16) << low << std::dec
-	    << " = "    << oss.str ()
-	    << std::endl;
+  oss << std::scientific << std::setprecision (22) << value;
 
   if (tolerance == 0)
     {
+      bool pass = oss.str () == str;
+  
+      std::cout << GetParent ()->GetName () << " Bug 1786: "
+		<< (pass ? "pass " : "FAIL ")
+		<< "    0x" << std::hex << std::setw (16) << low << std::dec
+		<< " = "    << oss.str ();
+      if (!pass)
+	{
+	  std::cout << ", expected " << str;
+	}
+      std::cout << std::endl;
+
       NS_TEST_EXPECT_MSG_EQ (oss.str (), str,
 			     "Fraction string not correct");
     }
   else
     {
-      // No obvious way to implement a tolerance
+      // No obvious way to implement a tolerance on the strings
+      
+      std::cout << GetParent ()->GetName () << " Bug 1786: "
+		<< "skip "
+		<< "    0x" << std::hex << std::setw (16) << low << std::dec
+		<< " = "    << oss.str ()
+		<< ", expected " << str
+		<< std::endl;
+
     }
 }
 void
 Int64x64Bug1786TestCase::DoRun (void)
 {
   std::cout << std::endl;
-  std::cout << GetParent ()->GetName () << ": " << GetName () << ":"
+  std::cout << GetParent ()->GetName () << " But 1786: " << GetName ()
 	    << std::endl;
 
   int64_t tolerance = 0;
@@ -520,72 +640,81 @@
       // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
       tolerance = 1;
     }
-  
-  Check (                 1ULL, "+0.000000000000000000054");
-  Check (                 2ULL, "+0.000000000000000000108");
-  Check (                 3ULL, "+0.000000000000000000162");
-  Check (                 4ULL, "+0.000000000000000000216");
-  Check (                 5ULL, "+0.000000000000000000271");
-  Check (                 6ULL, "+0.000000000000000000325");
-  Check (                 7ULL, "+0.000000000000000000379");
-  Check (                 8ULL, "+0.000000000000000000433");
-  Check (                 9ULL, "+0.000000000000000000487");
-  Check (               0xAULL, "+0.000000000000000000542");
-  Check (               0xFULL, "+0.000000000000000000813");
-  Check (              0xF0ULL, "+0.000000000000000013010");
-  Check (             0xF00ULL, "+0.000000000000000208166");
-  Check (            0xF000ULL, "+0.000000000000003330669");
-  Check (           0xF0000ULL, "+0.000000000000053290705");
-  Check (          0xF00000ULL, "+0.000000000000852651282");
-  Check (         0xF000000ULL, "+0.000000000013642420526");
-  Check (        0xF0000000ULL, "+0.000000000218278728425");
-  Check (       0xF00000000ULL, "+0.000000003492459654808");
-  Check (      0xF000000000ULL, "+0.000000055879354476928");
-  Check (     0xF0000000000ULL, "+0.000000894069671630859");
-  Check (    0xF00000000000ULL, "+0.000014305114746093750");
-  Check (   0xF000000000000ULL, "+0.000228881835937500000");
-  Check (  0xF0000000000000ULL, "+0.003662109375000000000");
+
+  // Some of these values differ from the DoubleTestCase
+  // by one count in the last place
+  // because operator<< truncates the last output digit,
+  // instead of rounding.
+  Check (                 1ULL, "+0.0000000000000000000542");
+  Check (                 2ULL, "+0.0000000000000000001084");
+  Check (                 3ULL, "+0.0000000000000000001626");
+  Check (                 4ULL, "+0.0000000000000000002168");
+  Check (                 5ULL, "+0.0000000000000000002710");
+  Check (                 6ULL, "+0.0000000000000000003253");
+  Check (                 7ULL, "+0.0000000000000000003795");
+  Check (                 8ULL, "+0.0000000000000000004337");
+  Check (                 9ULL, "+0.0000000000000000004879");
+  Check (               0xAULL, "+0.0000000000000000005421");
+  Check (               0xFULL, "+0.0000000000000000008132");
+  Check (              0xF0ULL, "+0.0000000000000000130104");
+  Check (             0xF00ULL, "+0.0000000000000002081668");
+  Check (            0xF000ULL, "+0.0000000000000033306691");
+  Check (           0xF0000ULL, "+0.0000000000000532907052");
+  Check (          0xF00000ULL, "+0.0000000000008526512829");
+  Check (         0xF000000ULL, "+0.0000000000136424205266");
+  Check (        0xF0000000ULL, "+0.0000000002182787284255");
+  Check (       0xF00000000ULL, "+0.0000000034924596548080");
+  Check (      0xF000000000ULL, "+0.0000000558793544769287");
+  Check (     0xF0000000000ULL, "+0.0000008940696716308594");
+  Check (    0xF00000000000ULL, "+0.0000143051147460937500");
+  Check (   0xF000000000000ULL, "+0.0002288818359375000000");
+  Check (  0xF0000000000000ULL, "+0.0036621093750000000000");
+  Check ( 0xF00000000000000ULL, "+0.0585937500000000000000");
   std::cout << std::endl;
-  Check (0x7FFFFFFFFFFFFFFDULL, "+0.499999999999999999837", tolerance);
-  Check (0x7FFFFFFFFFFFFFFEULL, "+0.499999999999999999891", tolerance);
-  Check (0x7FFFFFFFFFFFFFFFULL, "+0.499999999999999999945", tolerance);
-  Check (0x8000000000000000ULL, "+0.500000000000000000000");
-  Check (0x8000000000000001ULL, "+0.500000000000000000054", tolerance);
-  Check (0x8000000000000002ULL, "+0.500000000000000000108", tolerance);
-  Check (0x8000000000000003ULL, "+0.500000000000000000162", tolerance);
+  Check (0x7FFFFFFFFFFFFFFDULL, "+0.4999999999999999998374", tolerance);
+  Check (0x7FFFFFFFFFFFFFFEULL, "+0.4999999999999999998916", tolerance);
+  Check (0x7FFFFFFFFFFFFFFFULL, "+0.4999999999999999999458", tolerance);
+  Check (0x8000000000000000ULL, "+0.5000000000000000000000");
+  Check (0x8000000000000001ULL, "+0.5000000000000000000542", tolerance);
+  Check (0x8000000000000002ULL, "+0.5000000000000000001084", tolerance);
+  Check (0x8000000000000003ULL, "+0.5000000000000000001626", tolerance);
   std::cout << std::endl;
-  Check (0xF000000000000000ULL, "+0.937500000000000000000");
-  Check (0xFF00000000000000ULL, "+0.996093750000000000000");
-  Check (0xFFF0000000000000ULL, "+0.999755859375000000000");
-  Check (0xFFFF000000000000ULL, "+0.999984741210937500000");
-  Check (0xFFFFF00000000000ULL, "+0.999999046325683593750");
-  Check (0xFFFFFF0000000000ULL, "+0.999999940395355224609");
-  Check (0xFFFFFFF000000000ULL, "+0.999999996274709701538");
-  Check (0xFFFFFFFF00000000ULL, "+0.999999999767169356346");
-  Check (0xFFFFFFFFF0000000ULL, "+0.999999999985448084771");
-  Check (0xFFFFFFFFFF000000ULL, "+0.999999999999090505298");
-  Check (0xFFFFFFFFFFF00000ULL, "+0.999999999999943156581");
-  Check (0xFFFFFFFFFFFF0000ULL, "+0.999999999999996447286");
-  Check (0xFFFFFFFFFFFFF000ULL, "+0.999999999999999777955");
-  Check (0xFFFFFFFFFFFFFF00ULL, "+0.999999999999999986122");
-  Check (0xFFFFFFFFFFFFFFF0ULL, "+0.999999999999999999132");
-  Check (0xFFFFFFFFFFFFFFFFULL, "+0.999999999999999999945", tolerance);
+  Check (0xF000000000000000ULL, "+0.9375000000000000000000");
+  Check (0xFF00000000000000ULL, "+0.9960937500000000000000");
+  Check (0xFFF0000000000000ULL, "+0.9997558593750000000000");
+  Check (0xFFFF000000000000ULL, "+0.9999847412109375000000");
+  Check (0xFFFFF00000000000ULL, "+0.9999990463256835937500");
+  Check (0xFFFFFF0000000000ULL, "+0.9999999403953552246094");
+  Check (0xFFFFFFF000000000ULL, "+0.9999999962747097015381");
+  Check (0xFFFFFFFF00000000ULL, "+0.9999999997671693563461");
+  Check (0xFFFFFFFFF0000000ULL, "+0.9999999999854480847716");
+  Check (0xFFFFFFFFFF000000ULL, "+0.9999999999990905052982");
+  Check (0xFFFFFFFFFFF00000ULL, "+0.9999999999999431565811");
+  Check (0xFFFFFFFFFFFF0000ULL, "+0.9999999999999964472863");
+  Check (0xFFFFFFFFFFFFF000ULL, "+0.9999999999999997779554");
+  Check (0xFFFFFFFFFFFFFF00ULL, "+0.9999999999999999861222");
+  Check (0xFFFFFFFFFFFFFFF0ULL, "+0.9999999999999999991326");
+  Check (0xFFFFFFFFFFFFFFF5ULL, "+0.9999999999999999994037", tolerance);
+  Check (0xFFFFFFFFFFFFFFF6ULL, "+0.9999999999999999994579", tolerance);
+  Check (0xFFFFFFFFFFFFFFF7ULL, "+0.9999999999999999995121", tolerance);
+  Check (0xFFFFFFFFFFFFFFF8ULL, "+0.9999999999999999995663", tolerance);
+  Check (0xFFFFFFFFFFFFFFF9ULL, "+0.9999999999999999996205", tolerance);
+  Check (0xFFFFFFFFFFFFFFFAULL, "+0.9999999999999999996747", tolerance);
+  Check (0xFFFFFFFFFFFFFFFBULL, "+0.9999999999999999997289", tolerance);
+  Check (0xFFFFFFFFFFFFFFFCULL, "+0.9999999999999999997832", tolerance);
+  Check (0xFFFFFFFFFFFFFFFDULL, "+0.9999999999999999998374", tolerance);
+  Check (0xFFFFFFFFFFFFFFFEULL, "+0.9999999999999999998916", tolerance);
+  Check (0xFFFFFFFFFFFFFFFFULL, "+0.9999999999999999999458", tolerance);
 }
 
+
 class Int64x64CompareTestCase : public TestCase
 {
 public:
   Int64x64CompareTestCase ();
   virtual void DoRun (void);
 
-#if defined (__GNUC__)
-#if (__GNUC__ == 4 && (4 <= __GNUC_MINOR__ && __GNUC_MINOR__ <= 6))
-  // gcc-4.4 is overeager to optimize away signed comparisons
-  // which makes it hard to test comparison operators
-  __attribute__ ((optimize ("no-strict-overflow")))
-#endif
-#endif
-  void Check (const bool result, const bool expected,
+  void Check (const bool result, const bool expect,
 	      const std::string & msg);
 };
 Int64x64CompareTestCase::Int64x64CompareTestCase ()
@@ -593,21 +722,24 @@
 {
 }
 void
-Int64x64CompareTestCase::Check (const bool result, const bool expected,
+Int64x64CompareTestCase::Check (const bool result, const bool expect,
 				const std::string & msg)
 {
+  bool pass = result == expect;
+  
   std::cout << GetParent ()->GetName () << " Compare: "
-	    << (result == expected ? "pass:  " : "FAIL:  ") << msg
+	    << (pass ? "pass " : "FAIL ")
+	    << msg
 	    << std::endl;
   
-  NS_TEST_ASSERT_MSG_EQ (result, expected, msg);
+  NS_TEST_ASSERT_MSG_EQ (result, expect, msg);
 }
 
 void
 Int64x64CompareTestCase::DoRun (void)
 {
   std::cout << std::endl;
-  std::cout << GetParent ()->GetName () << ": " << GetName () << ":"
+  std::cout << GetParent ()->GetName () << " Compare: " << GetName ()
 	    << std::endl;
 
   const int64x64_t zero ( 0, 0);
@@ -621,62 +753,66 @@
   const int64x64_t monef = mone - frac;
   const int64x64_t mtwof = mtwo - frac;
   
-  Check ( zerof == zerof, true,  "equality, zero");
-  Check ( onef  == onef,  true,  "equality, positive");
-  Check ( mtwof == mtwof, true,  "equality, negative");
-  Check ( zero  == one,   false, "equality false, zero");
-  Check ( one   == two,   false, "equality false, unsigned");
-  Check ( one   == mone,  false, "equality false, signed");
-  Check ( onef  == one,   false, "equality false, fraction");
+  Check ( zerof    == zerof, true,  "equality, zero");
+  Check ( onef     == onef,  true,  "equality, positive");
+  Check ( mtwof    == mtwof, true,  "equality, negative");
+  Check ( zero     == one,   false, "equality false, zero");
+  Check ( one      == two,   false, "equality false, unsigned");
+  Check ( one      == mone,  false, "equality false, signed");
+  Check ( onef     == one,   false, "equality false, fraction");
   std::cout << std::endl;
 
-  Check ( zerof != zerof, false, "inequality, zero");
-  Check ( onef  != onef,  false, "inequality, positive");
-  Check ( mtwof != mtwof, false, "inequality, negative");
-  Check ( zero  != one,   true,  "inequality true, zero");
-  Check ( one   != two,   true,  "inequality true, unsigned");
-  Check ( one   != mone,  true,  "inequality true, signed");
-  Check ( onef  != one,   true,  "inequality true, fraction");
+  Check ( zerof    != zerof, false, "inequality, zero");
+  Check ( onef     != onef,  false, "inequality, positive");
+  Check ( mtwof    != mtwof, false, "inequality, negative");
+  Check ( zero     != one,   true,  "inequality true, zero");
+  Check ( one      != two,   true,  "inequality true, unsigned");
+  Check ( one      != mone,  true,  "inequality true, signed");
+  Check ( onef     != one,   true,  "inequality true, fraction");
   std::cout << std::endl;
 
-  Check ( zerof <  onef,  true,  "less, zerof");
-  Check ( zero  <  zerof, true,  "less, zero");
-  Check ( one   <  onef,  true,  "less, positive");
-  Check ( monef <  mone,  true,  "less, negative");
-  Check ( onef  <  one,   false, "less, false, positive");
-  Check ( mtwo  <  mtwof, false, "less, false, negative");
+  Check ( zerof    <  onef,  true,  "less, zerof");
+  Check ( zero     <  zerof, true,  "less, zero");
+  Check ( one      <  onef,  true,  "less, positive");
+  Check ( monef    <  mone,  true,  "less, negative");
+  Check ( onef     <  one,   false, "less, false, positive");
+  Check ( mtwo     <  mtwof, false, "less, false, negative");
   std::cout << std::endl;
 
-  Check ( zerof <= zerof, true,  "less equal, equal, zerof");
-  Check ( zero  <= zerof, true,  "less equal, less, zero");
-  Check ( onef  <= onef,  true,  "less equal, equal, positive");
-  Check ( monef <= mone,  true,  "less equal, less, negative");
-  Check ( onef  <= one,   false, "less equal, false, positive");
-  Check ( mtwo  <= mtwof, false, "less equal, false, negative");
+  Check ( zerof    <= zerof, true,  "less equal, equal, zerof");
+  Check ( zero     <= zerof, true,  "less equal, less, zero");
+  Check ( onef     <= onef,  true,  "less equal, equal, positive");
+  Check ( monef    <= mone,  true,  "less equal, less, negative");
+  Check ( onef     <= one,   false, "less equal, false, positive");
+  Check ( mtwo     <= mtwof, false, "less equal, false, negative");
+  std::cout << std::endl;
+
+  Check ( onef     >  zerof, true,  "greater, zerof");
+  Check ( zerof    >  zero,  true,  "greater, zero");
+  Check ( onef     >  one,   true,  "greater, positive");
+  Check ( mone     >  monef, true,  "greater, negative");
+  Check ( one      >  onef,  false, "greater, false, positive");
+  Check ( mtwof    >  mtwo,  false, "greater, false, negative");
   std::cout << std::endl;
 
-  Check ( onef  >  zerof, true,  "greater, zerof");
-  Check ( zerof >  zero,  true,  "greater, zero");
-  Check ( onef  >  one,   true,  "greater, positive");
-  Check ( mone  >  monef, true,  "greater, negative");
-  Check ( one   >  onef,  false, "greater, false, positive");
-  Check ( mtwof >  mtwo,  false, "greater, false, negative");
+  Check ( zerof    >= zerof, true,  "greater equal, equal, zerof");
+  Check ( zerof    >= zero,  true,  "greater equal, greater, zero");
+  Check ( onef     >= onef,  true,  "greater equal, equal, positive");
+  Check ( mone     >= monef, true,  "greater equal, greater, negative");
+  Check ( one      >= onef,  false, "greater equal, false, positive");
+  Check ( mtwof    >= mtwo,  false, "greater equal, false, negative");
   std::cout << std::endl;
 
-  Check ( zerof >= zerof, true,  "greater equal, equal, zerof");
-  Check ( zerof >= zero,  true,  "greater equal, greater, zero");
-  Check ( onef  >= onef,  true,  "greater equal, equal, positive");
-  Check ( mone  >= monef, true,  "greater equal, greater, negative");
-  Check ( one   >= onef,  false, "greater equal, false, positive");
-  Check ( mtwof >= mtwo,  false, "greater equal, false, negative");
-  std::cout << std::endl;
+  Check ( zero     == false, true,  "zero   == false");
+  Check ( one      == true,  true,  "one    == true");
+  Check ( zerof    != false, true,  "zerof  != false");
+  Check ( (!zero)  == true,  true,  "!zero  == true");
+  Check ( (!zerof) == false, true,  "!zerof == false");
+  Check ( (!one)   == false, true,  "!one   == false");
+  Check ( (+onef)  == onef,  true, "unary positive");
+  Check ( (-onef)  == monef, true, "unary negative");
+}
 
-  Check ( (!zero)  == one,  true,  "not zero");
-  Check ( (!zerof) == zero, true,  "not zerof");
-  Check ( (!one)   == zero, true,  "not one");
-  Check ( (+onef) == onef, true, "unary positive");
-  Check ( (-onef) == monef, true, "unary negative");
-}
 
 class Int64x64InvertTestCase : public TestCase
 {
@@ -685,7 +821,7 @@
   virtual void DoRun (void);
   void Check (const int64_t factor);
   void CheckCase (const uint64_t factor,
-		  const int64x64_t result, const int64x64_t expected,
+		  const int64x64_t result, const int64x64_t expect,
 		  const std::string & msg,
 		  const double tolerance = 0);
 };
@@ -697,27 +833,30 @@
 void
 Int64x64InvertTestCase::CheckCase (const uint64_t factor,
 				   const int64x64_t result,
-				   const int64x64_t expected,
+				   const int64x64_t expect,
 				   const std::string & msg,
 				   const double tolerance /* = 0 */)
 {
-  std::cout << GetParent ()->GetName () << " Invert: "
-	    << factor << ": ";
-  if (result == expected)
+  bool pass = Abs (result - expect) <= tolerance;
+  
+  std::cout << GetParent ()->GetName () << " Invert: ";
+
+  if (pass)
     {
-      std::cout << "pass:  ";
+      std::cout << "pass:  " << factor << ": ";
+
     }
   else
     {
-      std::cout << "FAIL:  "
+      std::cout << "FAIL:  " << factor << ": "
 		<< "(res: " << result
-		<< " exp: " << expected
+		<< " exp: " << expect
 		<< " tol: " << tolerance << ")  ";
     }
   std::cout << msg 
 	    << std::endl;
   
-  NS_TEST_ASSERT_MSG_EQ_TOL (result, expected, int64x64_t(tolerance), msg);
+  NS_TEST_ASSERT_MSG_EQ_TOL (result, expect, int64x64_t(tolerance), msg);
 }
 
 void
@@ -756,7 +895,7 @@
 Int64x64InvertTestCase::DoRun (void)
 {
   std::cout << std::endl;
-  std::cout << GetParent ()->GetName () << ": " << GetName () << ":"
+  std::cout << GetParent ()->GetName () << " Invert: " << GetName ()
 	    << std::endl;
   
   Check (2);
@@ -784,6 +923,216 @@
 }
 
 
+class Int64x64DoubleTestCase : public TestCase
+{
+public:
+  Int64x64DoubleTestCase ();
+  virtual void DoRun (void);
+  void Check (const int64_t intPart);
+  void Check (const long double value,
+	      const int64_t intPart,
+	      const uint64_t lo);
+private:
+  long double m_last;
+  int64x64_t  m_deltaMax;
+  int         m_deltaCount;
+};
+
+Int64x64DoubleTestCase::Int64x64DoubleTestCase ()
+  : TestCase ("Construct from floating point.")
+{
+}
+
+void
+Int64x64DoubleTestCase::Check (const long double value,
+			       const int64_t intPart,
+			       const uint64_t lo)
+{
+  // Construct the expected value
+  int64x64_t expect = int64x64_t (0, lo);
+  expect += intPart;
+
+  // Actual value of conversion from double
+  const int64x64_t result = int64x64_t (value);
+
+  // Make tolerance depend on magnitude of value
+  long double margin = 0;
+  if (int64x64_t::implementation == int64x64_t::ld_impl)
+    {
+      // Darwin 12.5.0 (Mac 10.8.5) g++ 4.2.1
+      margin = 1.0;
+    }
+  
+  const int64x64_t tolerance = (margin + std::fabs (value))
+    * std::numeric_limits<long double>::epsilon ();
+  
+  const int64x64_t delta = Abs (result - expect);
+  const bool skip = value == m_last;
+  const bool pass = delta <= tolerance;
+  
+  // Save stream format flags
+  std::ios_base::fmtflags ff = std::cout.flags ();
+  std::cout << std::fixed << std::setprecision (22);
+  
+  std::cout << GetParent ()->GetName () << " Double: "
+	    << (skip ? "skip " : (pass ? "pass " : "FAIL "))
+	    << std::showpos << value << " == " 
+	    << Printer (result)
+	    << std::endl;
+  
+  // Log non-zero delta
+  if ( delta > int64x64_t() )
+    {
+      std::cout << GetParent ()->GetName ()
+		<< std::left  << std::setw (43) << "         expected"
+		<< std::right << Printer (expect)
+		<< std::endl;
+
+      if (delta == tolerance)
+	{
+	  std::cout << GetParent ()->GetName ()
+		    << std::left  << std::setw (43) << "         delta = tolerance"
+		    << std::right << Printer (delta)
+		    << std::endl;
+	}
+      else
+	{
+	  std::cout << GetParent ()->GetName ()
+		    << std::left  << std::setw (43) << "         delta"
+		    << std::right << Printer (delta)
+		    << std::endl;
+	  std::cout << GetParent ()->GetName ()
+		    << std::left  << std::setw (43) << "         +/-"
+		    << std::right << Printer (tolerance)
+		    << std::endl;
+	}
+      
+      ++m_deltaCount;
+      
+      if ( delta > m_deltaMax )
+	{
+	  m_deltaMax = delta;
+	}
+    }
+  
+  NS_TEST_ASSERT_MSG_EQ_TOL (result, expect, tolerance,
+			     "int64x64_t (long double) failed");
+  m_last = value;
+  std::cout.flags (ff);
+
+}
+
+void
+Int64x64DoubleTestCase::Check (const int64_t intPart)
+{
+  std::cout << std::endl;
+  std::cout << GetParent ()->GetName () << " Double: "
+	    << "integer: " << intPart
+	    << std::endl;
+  m_last = intPart;
+  m_deltaCount = 0;
+
+  // Nudging the integer part eliminates deltas around 0
+  long double v = intPart;
+  
+  Check (v +0.0000000000000000000542L, intPart,                0x1ULL);
+  Check (v +0.0000000000000000001084L, intPart,                0x2ULL);
+  Check (v +0.0000000000000000001626L, intPart,                0x3ULL);
+  Check (v +0.0000000000000000002168L, intPart,                0x4ULL);
+  Check (v +0.0000000000000000002710L, intPart,                0x5ULL);
+  Check (v +0.0000000000000000003253L, intPart,                0x6ULL);
+  Check (v +0.0000000000000000003795L, intPart,                0x7ULL);
+  Check (v +0.0000000000000000004337L, intPart,                0x8ULL);
+  Check (v +0.0000000000000000004879L, intPart,                0x9ULL);
+  Check (v +0.0000000000000000005421L, intPart,                0xAULL);
+  Check (v +0.0000000000000000008132L, intPart,                0xFULL);
+  Check (v +0.0000000000000000130104L, intPart,               0xF0ULL);
+  Check (v +0.0000000000000002081668L, intPart,              0xF00ULL);
+  Check (v +0.0000000000000033306691L, intPart,             0xF000ULL);
+  Check (v +0.0000000000000532907052L, intPart,            0xF0000ULL);
+  Check (v +0.0000000000008526512829L, intPart,           0xF00000ULL);
+  Check (v +0.0000000000136424205266L, intPart,          0xF000000ULL);
+  Check (v +0.0000000002182787284255L, intPart,         0xF0000000ULL);
+  Check (v +0.0000000034924596548080L, intPart,        0xF00000000ULL);
+  Check (v +0.0000000558793544769287L, intPart,       0xF000000000ULL);
+  Check (v +0.0000008940696716308594L, intPart,      0xF0000000000ULL);
+  Check (v +0.0000143051147460937500L, intPart,     0xF00000000000ULL);
+  Check (v +0.0002288818359375000000L, intPart,    0xF000000000000ULL);
+  Check (v +0.0036621093750000000000L, intPart,   0xF0000000000000ULL);
+  Check (v +0.0585937500000000000000L, intPart,  0xF00000000000000ULL);
+  std::cout << std::endl;
+  Check (v +0.4999999999999999998374L, intPart, 0x7FFFFFFFFFFFFFFDULL);
+  Check (v +0.4999999999999999998916L, intPart, 0x7FFFFFFFFFFFFFFEULL);
+  Check (v +0.4999999999999999999458L, intPart, 0x7FFFFFFFFFFFFFFFULL);
+  Check (v +0.5000000000000000000000L, intPart, 0x8000000000000000ULL);
+  Check (v +0.5000000000000000000542L, intPart, 0x8000000000000001ULL);
+  Check (v +0.5000000000000000001084L, intPart, 0x8000000000000002ULL);
+  Check (v +0.5000000000000000001626L, intPart, 0x8000000000000003ULL);
+  std::cout << std::endl;
+  Check (v +0.9375000000000000000000L, intPart, 0xF000000000000000ULL);
+  Check (v +0.9960937500000000000000L, intPart, 0xFF00000000000000ULL);
+  Check (v +0.9997558593750000000000L, intPart, 0xFFF0000000000000ULL);
+  Check (v +0.9999847412109375000000L, intPart, 0xFFFF000000000000ULL);
+  Check (v +0.9999990463256835937500L, intPart, 0xFFFFF00000000000ULL);
+  Check (v +0.9999999403953552246094L, intPart, 0xFFFFFF0000000000ULL);
+  Check (v +0.9999999962747097015381L, intPart, 0xFFFFFFF000000000ULL);
+  Check (v +0.9999999997671693563461L, intPart, 0xFFFFFFFF00000000ULL);
+  Check (v +0.9999999999854480847716L, intPart, 0xFFFFFFFFF0000000ULL);
+  Check (v +0.9999999999990905052982L, intPart, 0xFFFFFFFFFF000000ULL);
+  Check (v +0.9999999999999431565811L, intPart, 0xFFFFFFFFFFF00000ULL);
+  Check (v +0.9999999999999964472863L, intPart, 0xFFFFFFFFFFFF0000ULL);
+  Check (v +0.9999999999999997779554L, intPart, 0xFFFFFFFFFFFFF000ULL);
+  Check (v +0.9999999999999999861222L, intPart, 0xFFFFFFFFFFFFFF00ULL);
+  Check (v +0.9999999999999999991326L, intPart, 0xFFFFFFFFFFFFFFF0ULL);
+  Check (v +0.9999999999999999994037L, intPart, 0xFFFFFFFFFFFFFFF5ULL);
+  Check (v +0.9999999999999999994579L, intPart, 0xFFFFFFFFFFFFFFF6ULL);
+  Check (v +0.9999999999999999995121L, intPart, 0xFFFFFFFFFFFFFFF7ULL);
+  Check (v +0.9999999999999999995663L, intPart, 0xFFFFFFFFFFFFFFF8ULL);
+  Check (v +0.9999999999999999996205L, intPart, 0xFFFFFFFFFFFFFFF9ULL);
+  Check (v +0.9999999999999999996747L, intPart, 0xFFFFFFFFFFFFFFFAULL);
+  Check (v +0.9999999999999999997289L, intPart, 0xFFFFFFFFFFFFFFFBULL);
+  Check (v +0.9999999999999999997832L, intPart, 0xFFFFFFFFFFFFFFFCULL);
+  Check (v +0.9999999999999999998374L, intPart, 0xFFFFFFFFFFFFFFFDULL);
+  Check (v +0.9999999999999999998916L, intPart, 0xFFFFFFFFFFFFFFFEULL);
+  Check (v +0.9999999999999999999458L, intPart, 0xFFFFFFFFFFFFFFFFULL);
+
+  std::cout << GetParent ()->GetName () << " Double: "
+	    << "integer: " << intPart
+	    << ": delta count: " << m_deltaCount
+	    << ", max: " << Printer (m_deltaMax)
+	    << std::endl;  
+}
+
+void
+Int64x64DoubleTestCase::DoRun (void)
+{
+  std::cout << std::endl;
+  std::cout << GetParent ()->GetName () << " Double: " << GetName ()
+	    << std::endl;
+
+  // Save stream format flags
+  std::ios_base::fmtflags ff = std::cout.flags ();
+  std::cout << std::scientific << std::setprecision (21);
+
+  m_deltaMax = int64x64_t ();
+
+  std::cout << GetParent ()->GetName () << " Double: "
+	    << std::endl;
+    
+  Check (-2);
+  Check (-1);
+  Check ( 0);
+  Check ( 1);
+  Check ( 2);
+
+  std::cout << GetParent ()->GetName () << " Double: "
+	    << "max delta: " << Printer (m_deltaMax)
+	    << std::endl;
+
+  std::cout.flags (ff);
+}
+
+
 class Int64x64ImplTestCase : public TestCase
 {
 public:
@@ -800,7 +1149,7 @@
 Int64x64ImplTestCase::DoRun (void)
 {
   std::cout << std::endl;
-  std::cout << GetParent ()->GetName () << ": " << GetName () << ":"
+  std::cout << GetParent ()->GetName () << " Impl: " << GetName ()
 	    << std::endl;
 
   
@@ -818,16 +1167,16 @@
   std::cout << "cairo_impl64:  " << cairo_impl64 << std::endl;
   std::cout << "cairo_impl128: " << cairo_impl128 << std::endl;
 #endif
-
-  std::cout << std::endl;
 }
 
-static class Int64x64128TestSuite : public TestSuite
+
+static class Int64x64TestSuite : public TestSuite
 {
 public:
-  Int64x64128TestSuite ()
+  Int64x64TestSuite ()
     : TestSuite ("int64x64", UNIT)
   {
+    AddTestCase (new Int64x64ImplTestCase (), TestCase::QUICK);
     AddTestCase (new Int64x64HiLoTestCase (), TestCase::QUICK);
     AddTestCase (new Int64x64ArithmeticTestCase (), TestCase::QUICK);
     AddTestCase (new Int64x64CompareTestCase (), TestCase::QUICK);
@@ -837,6 +1186,13 @@
     AddTestCase (new Int64x64Bug863TestCase (), TestCase::QUICK);
     AddTestCase (new Int64x64Bug1786TestCase (), TestCase::QUICK);
     AddTestCase (new Int64x64InvertTestCase (), TestCase::QUICK);
-    AddTestCase (new Int64x64ImplTestCase (), TestCase::QUICK);
+    AddTestCase (new Int64x64DoubleTestCase (), TestCase::QUICK);
   }
-} g_int64x64TestSuite;
+}  g_int64x64TestSuite;
+
+}  // namespace test
+
+}  // namespace int64x64
+
+}  // namespace ns3
+