diff --git a/src/simulator/high-precision-128.cc b/src/simulator/high-precision-128.cc index 7fc3e3888..a61d03fd2 100644 --- a/src/simulator/high-precision-128.cc +++ b/src/simulator/high-precision-128.cc @@ -221,25 +221,48 @@ HighPrecision::Div (HighPrecision const &o) HP128INC (m_ndivs++); EnsureSlow (); const_cast (o).EnsureSlow (); - cairo_quorem128_t qr; - qr = _cairo_int128_divrem (m_slowValue, o.m_slowValue); - m_slowValue = _cairo_int128_lsl (qr.quo, 64); + + cairo_int128_t result = Div128 (m_slowValue, o.m_slowValue); + m_slowValue = result; + return false; +} + +cairo_int128_t +HighPrecision::Div128 (cairo_int128_t sa, cairo_int128_t sb) +{ + 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 - cairo_int128_t div = o.m_slowValue; - cairo_int128_t tmp; - tmp = _cairo_int128_rsa (qr.rem, 64); - cairo_int128_t zero = _cairo_int64_to_int128 (0); - if (_cairo_int128_eq (tmp, zero)) + cairo_uint128_t tmp = _cairo_uint128_rsl (qr.rem, 64); + cairo_uint128_t zero = _cairo_uint64_to_uint128 (0); + cairo_uint128_t rem, div; + if (_cairo_uint128_eq (tmp, zero)) { - qr.rem = _cairo_int128_lsl (qr.rem, 64); + rem = _cairo_uint128_lsl (qr.rem, 64); + div = b; } else { - div = _cairo_int128_rsa (div, 64); + rem = qr.rem; + div = _cairo_uint128_rsl (b, 64); } - qr = _cairo_int128_divrem (qr.rem, div); - m_slowValue = _cairo_int128_add (m_slowValue, qr.quo); - return false; + 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); } int HighPrecision::SlowCompare (HighPrecision const &o) const @@ -428,6 +451,37 @@ Hp128Bug455TestCase::DoRun (void) } +class Hp128Bug863TestCase : public TestCase +{ +public: + Hp128Bug863TestCase(); + virtual bool DoRun (void); +}; + +Hp128Bug863TestCase::Hp128Bug863TestCase() + : TestCase("Test case for bug 863") +{} +bool +Hp128Bug863TestCase::DoRun (void) +{ + HighPrecision a = HighPrecision (0.9); + a.Div (HighPrecision (1)); + NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 0.9, "The original testcase"); + a = HighPrecision (0.5); + a.Div(HighPrecision (0.5)); + NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 1.0, "Simple test for division"); + a = HighPrecision (-0.5); + a.Div(HighPrecision (0.5)); + NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -1.0, "first argument negative"); + a = HighPrecision (0.5); + a.Div(HighPrecision (-0.5)); + NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), -1.0, "second argument negative"); + a = HighPrecision (-0.5); + a.Div(HighPrecision (-0.5)); + NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 1.0, "both arguments negative"); + + return false; +} static class HighPrecision128TestSuite : public TestSuite { @@ -437,6 +491,7 @@ public: { AddTestCase (new Hp128ArithmeticTestCase()); AddTestCase (new Hp128Bug455TestCase()); + AddTestCase (new Hp128Bug863TestCase()); } } g_highPrecision128TestSuite; diff --git a/src/simulator/high-precision-128.h b/src/simulator/high-precision-128.h index 853fb3e9a..779da0f27 100644 --- a/src/simulator/high-precision-128.h +++ b/src/simulator/high-precision-128.h @@ -106,6 +106,7 @@ private: bool SlowMul (HighPrecision const &o); int SlowCompare (HighPrecision const &o) const; cairo_uint128_t Mul128(cairo_uint128_t , cairo_uint128_t ); + cairo_int128_t Div128 (cairo_int128_t sa, cairo_int128_t sb); inline void EnsureSlow (void); static const double MAX_64; diff --git a/src/simulator/time.cc b/src/simulator/time.cc index 1501fb7be..d09f20e22 100644 --- a/src/simulator/time.cc +++ b/src/simulator/time.cc @@ -683,6 +683,24 @@ ConversionTestCase::DoRun (void) } #endif +class Bug863TestCase : public TestCase +{ +public: + Bug863TestCase (); + virtual bool DoRun (void); +}; + +Bug863TestCase::Bug863TestCase () + : TestCase ("Bug 863") +{} + +bool Bug863TestCase::DoRun (void) +{ + Scalar result = Scalar (0.9) / Scalar (1.0); + NS_TEST_ASSERT_MSG_EQ ((result == Scalar (0.9)), true, "Invalid arithmetic result"); + return false; +} + static class TimeTestSuite : public TestSuite { public: @@ -693,6 +711,7 @@ public: AddTestCase(new OperationsTimeTestCase()); AddTestCase(new TimeStepTestCase()); AddTestCase(new GlobalPrecisionTestCase()); + AddTestCase (new Bug863TestCase ()); //AddTestCase(new ConversionTestCase()); } } g_timeTestSuite;