# HG changeset patch # User Faker Moatamri # Date 1240472116 -7200 # Node ID 7d096e399d7795d46171f419b1085a22c5fd4f39 # Parent 489abe44ed7e5b2c060c213b09a34dd104f3020a bug 533: Multiplication of Scalar variables does not give expected result diff -r 489abe44ed7e -r 7d096e399d77 src/simulator/high-precision-128.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 #include @@ -151,10 +152,69 @@ { EnsureSlow (); const_cast (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; diff -r 489abe44ed7e -r 7d096e399d77 src/simulator/high-precision-128.h --- 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; diff -r 489abe44ed7e -r 7d096e399d77 src/simulator/time.cc --- 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);