bug 533: Multiplication of Scalar variables does not give expected result
authorFaker Moatamri <faker.moatamri@sophia.inria.fr>
Thu, 23 Apr 2009 09:35:16 +0200
changeset 4396 7d096e399d77
parent 4395 489abe44ed7e
child 4397 fd344e3bceac
bug 533: Multiplication of Scalar variables does not give expected result
src/simulator/high-precision-128.cc
src/simulator/high-precision-128.h
src/simulator/time.cc
--- a/src/simulator/high-precision-128.cc	Wed Apr 22 17:22:41 2009 +0200
+++ b/src/simulator/high-precision-128.cc	Thu Apr 23 09:35:16 2009 +0200
@@ -19,6 +19,7 @@
  */
 #include "high-precision-128.h"
 #include "ns3/test.h"
+#include "ns3/fatal-error.h"
 #include <math.h>
 #include <iostream>
 
@@ -151,10 +152,69 @@
 {
   EnsureSlow ();
   const_cast<HighPrecision &> (o).EnsureSlow ();
-  cairo_int128_t other = _cairo_int128_rsa (o.m_slowValue, 64);
-  m_slowValue = _cairo_int128_mul (m_slowValue, other);
+  //use the 128 bits multiplication
+  m_slowValue = Mul128(m_slowValue,o.m_slowValue);
   return false;
 }
+/**
+ * this function multiplies two 128 bits fractions considering
+ * the high 64 bits as the integer part and the low 64 bits
+ * as the fractional part. It takes into account the sign
+ * of the operands to produce a signed 128 bits result.
+ */
+cairo_int128_t
+HighPrecision::Mul128(cairo_int128_t a, cairo_int128_t b )
+{
+  //Implement the 128 bits multiplication
+  cairo_int128_t result;
+  cairo_uint128_t hiPart,loPart,midPart;
+  bool resultNegative = false, signA = false,signB = false;
+
+  //take the sign of the operands
+  signA = _cairo_int128_negative (a);
+  signB = _cairo_int128_negative (b);
+  //the result is negative only if one of the operand is negative
+  if ((signA == true && signB == false) ||(signA == false && signB == true))
+    {
+  	 resultNegative = true;
+    }
+  //now take the absolute part to make sure that the resulting operands are positive
+  if (signA == true)
+  {
+	  a = _cairo_int128_negate (a);
+  }
+  if (signB == true)
+  {
+  	  b = _cairo_int128_negate (b);
+  }
+
+  //Multiplying (a.h 2^64 + a.l) x (b.h 2^64 + b.l) =
+  //			2^128 a.h b.h + 2^64*(a.h b.l+b.h a.l) + a.l b.l
+  //get the low part a.l b.l
+  //multiply the fractional part
+  loPart = _cairo_uint64x64_128_mul (a.lo, b.lo);
+  //compute the middle part 2^64*(a.h b.l+b.h a.l)
+  midPart = _cairo_uint128_add(_cairo_uint64x64_128_mul(a.lo, b.hi),
+		  _cairo_uint64x64_128_mul(a.hi, b.lo)) ;
+  //truncate the low part
+  result.lo = _cairo_uint64_add(loPart.hi,midPart.lo);
+  //compute the high part 2^128 a.h b.h
+  hiPart = _cairo_uint64x64_128_mul (a.hi, b.hi);
+  //truncate the high part and only use the low part
+  result.hi = _cairo_uint64_add(hiPart.lo,midPart.hi);
+  //if the high part is not zero, put a warning
+  if (hiPart.hi !=0)
+  {
+	  NS_FATAL_ERROR("High precision 128 bits multiplication error: multiplication overflow.");
+  }
+  //add the sign to the result
+  if (resultNegative)
+  {
+	 result = _cairo_int128_negate (result);
+  }
+  return result;
+}
+
 bool 
 HighPrecision::Div (HighPrecision const &o)
 {
@@ -351,6 +411,22 @@
   a = HighPrecision (0.1);
   a.Div (HighPrecision (1.25));
   NS_TEST_ASSERT_EQUAL (a.GetDouble (), 0.08);
+  //test the multiplication
+  a = HighPrecision (0.5);
+  a.Mul(HighPrecision (5));
+  NS_TEST_ASSERT_EQUAL (a.GetDouble (), 2.5);
+  //test the sign of multiplication, first operand negative
+  a = HighPrecision (-0.5);
+  a.Mul(HighPrecision (5));
+  NS_TEST_ASSERT_EQUAL (a.GetDouble (), -2.5);
+  //two negative
+  a = HighPrecision (-0.5);
+  a.Mul(HighPrecision (-5));
+  NS_TEST_ASSERT_EQUAL (a.GetDouble (), 2.5);
+  //second operand negative
+  a = HighPrecision (0.5);
+  a.Mul(HighPrecision (-5));
+  NS_TEST_ASSERT_EQUAL (a.GetDouble (), -2.5);
 
 
   return result;
--- a/src/simulator/high-precision-128.h	Wed Apr 22 17:22:41 2009 +0200
+++ b/src/simulator/high-precision-128.h	Thu Apr 23 09:35:16 2009 +0200
@@ -85,6 +85,7 @@
   bool SlowSub (HighPrecision const &o);
   bool SlowMul (HighPrecision const &o);
   int SlowCompare (HighPrecision const &o) const;
+  cairo_uint128_t  Mul128(cairo_uint128_t , cairo_uint128_t );
   inline void EnsureSlow (void);
 
   static const double MAX_64;
--- a/src/simulator/time.cc	Wed Apr 22 17:22:41 2009 +0200
+++ b/src/simulator/time.cc	Thu Apr 23 09:35:16 2009 +0200
@@ -572,11 +572,11 @@
 
   Time t4;
   t4 = Seconds (10.0) * Scalar (1.5);
-  CheckTimeSec("old 11", t4.GetSeconds(), 10, ok);
+  CheckTimeSec("old 11", t4.GetSeconds(), 15, ok);
 
   Time t5;
   t5 = NanoSeconds (10) * Scalar (1.5);
-  CheckTime("old 12", t5.GetNanoSeconds(), 10, ok);
+  CheckTime("old 12", t5.GetNanoSeconds(), 15, ok);
 
   t4 = Seconds (10.0) * Scalar (15) / Scalar (10);
   CheckTimeSec("old 13", t4.GetSeconds(), 15, ok);