--- a/src/core/model/int64x64.cc Fri Jan 10 17:22:45 2014 -0800
+++ b/src/core/model/int64x64.cc Fri Jan 10 17:24:06 2014 -0800
@@ -14,34 +14,13 @@
namespace ns3 {
-static uint8_t MostSignificantDigit (uint64_t value)
-{
- uint8_t n = 0;
- do
- {
- n++;
- value /= 10;
- } while (value != 0);
- return n;
-}
-
-static uint64_t PowerOfTen (uint8_t n)
-{
- uint64_t retval = 1;
- while (n > 0)
- {
- retval *= 10;
- n--;
- }
- return retval;
-}
-
std::ostream &operator << (std::ostream &os, const int64x64_t &value)
{
int64_t hi = value.GetHigh ();
// Save stream format flags
std::ios_base::fmtflags ff = os.flags ();
+ os << std::setw (1);
{ /// \internal
/// See \bugid{1737}: gcc libstc++ 4.2 bug
@@ -55,24 +34,41 @@
}
}
- os << hi << ".";
- os.flags (ff); // Restore stream flags
+ os << std::right << hi << ".";
+
+ os << std::noshowpos;
- uint64_t low = value.GetLow ();
- uint8_t msd = MostSignificantDigit (~((uint64_t)0));
- do
+ int64x64_t low(0, value.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?
+
+ do
{
- msd--;
- uint64_t pow = PowerOfTen (msd);
- uint8_t digit = low / pow;
- NS_ASSERT (digit < 10);
- os << (uint16_t) digit;
- low -= digit * pow;
- } while (msd > 0 && low > 0);
+ low = 10 * low;
+ int64_t digit = low.GetHigh ();
+ low -= digit;
+
+ os << std::setw (1) << digit;
+
+ ++places;
+ if (floatfield)
+ {
+ more = places < os.precision ();
+ }
+ else // default
+ {
+ // Full resolution is 20 decimal digits
+ more = low.GetLow () && (places < 20);
+ }
+
+ } while (more);
+
+ os.flags (ff); // Restore stream flags
return os;
}
-static uint64_t ReadDigits (std::string str)
+static uint64_t ReadHiDigits (std::string str)
{
const char *buf = str.c_str ();
uint64_t retval = 0;
@@ -85,6 +81,22 @@
return retval;
}
+static uint64_t ReadLoDigits (std::string str)
+{
+ int64x64_t low (0, 0);
+ const int64x64_t round (0, 5);
+
+ for (std::string::const_reverse_iterator rchar = str.rbegin ();
+ rchar != str.rend ();
+ ++rchar)
+ {
+ int digit = *rchar - '0';
+ low = (low + digit + round) / 10;
+ }
+
+ return low.GetLow ();
+}
+
std::istream &operator >> (std::istream &is, int64x64_t &value)
{
std::string str;
@@ -121,12 +133,12 @@
next = str.find (".", cur);
if (next != std::string::npos)
{
- hi = ReadDigits (str.substr (cur, next-cur));
- lo = ReadDigits (str.substr (next+1, str.size ()-(next+1)));
+ hi = ReadHiDigits (str.substr (cur, next-cur));
+ lo = ReadLoDigits (str.substr (next+1, str.size ()-(next+1)));
}
else
{
- hi = ReadDigits (str.substr (cur, str.size ()-cur));
+ hi = ReadHiDigits (str.substr (cur, str.size ()-cur));
lo = 0;
}
hi = negative ? -hi : hi;
--- a/src/core/test/int64x64-test-suite.cc Fri Jan 10 17:22:45 2014 -0800
+++ b/src/core/test/int64x64-test-suite.cc Fri Jan 10 17:24:06 2014 -0800
@@ -1,6 +1,8 @@
#include "ns3/int64x64.h"
#include "ns3/test.h"
+#include <iomanip>
+
using namespace ns3;
class Int64x64FracTestCase : public TestCase
@@ -71,8 +73,8 @@
CheckString ("-1.0", -1, 0);
CheckString ("-1.0000", -1, 0);
CheckString ("1.0000000", 1, 0);
- CheckString ("1.08446744073709551615", 1, 8446744073709551615LL);
- CheckString ("-1.08446744073709551615", -1, 8446744073709551615LL);
+ CheckString (" 1.000000000000000000054", 1, 1);
+ CheckString ("-1.000000000000000000054", -1, 1);
}
class Int64x64InputOutputTestCase : public TestCase
@@ -94,19 +96,20 @@
int64x64_t value;
iss >> value;
std::ostringstream oss;
- oss << value;
+ oss << std::scientific << std::setprecision (21) << value;
NS_TEST_EXPECT_MSG_EQ (oss.str (), str, "Converted string does not match expected string");
}
void
Int64x64InputOutputTestCase::DoRun (void)
{
- CheckString ("+1.0");
- CheckString ("-1.0");
- CheckString ("+20.0");
- CheckString ("+1.08446744073709551615");
- CheckString ("-1.08446744073709551615");
- CheckString ("+1.18446744073709551615");
- CheckString ("-1.18446744073709551615");
+ CheckString ("+1.000000000000000000000");
+ CheckString ("+0.000000000000000000000");
+ CheckString ("-1.000000000000000000000");
+ CheckString ("+20.000000000000000000000");
+ CheckString ("+1.084467440737095516158");
+ CheckString ("-1.084467440737095516158");
+ CheckString ("+1.184467440737095516179");
+ CheckString ("-1.184467440737095516179");
}
#define CHECK_EXPECTED(a,b) \
@@ -239,6 +242,90 @@
NS_TEST_ASSERT_MSG_EQ (a.GetDouble (), 1.0, "both arguments negative");
}
+/**
+ * See \bugid{1786}
+ */
+class Int64x64Bug1786TestCase : public TestCase
+{
+public:
+ Int64x64Bug1786TestCase ();
+ void Check (const uint64_t low, const std::string & value);
+ virtual void DoRun (void);
+};
+
+Int64x64Bug1786TestCase::Int64x64Bug1786TestCase ()
+ : TestCase ("Test case for bug 1786")
+{
+}
+void
+Int64x64Bug1786TestCase::Check (const uint64_t low, const std::string & str)
+{
+ int64x64_t value (0, low);
+ std::ostringstream oss;
+ oss << std::scientific << std::setprecision (21) << value;
+ std::cout << " 0x" << std::hex << std::setw (16) << low << std::dec
+ << " = " << oss.str ()
+ << std::endl;
+ NS_TEST_EXPECT_MSG_EQ (oss.str (), str, "Fraction string not correct");
+}
+void
+Int64x64Bug1786TestCase::DoRun (void)
+{
+ std::cout << std::endl;
+ std::cout << GetName () << ":" << std::endl;
+
+ 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");
+ std::cout << std::endl;
+ Check (0x7FFFFFFFFFFFFFFDULL, "+0.499999999999999999837");
+ Check (0x7FFFFFFFFFFFFFFEULL, "+0.499999999999999999891");
+ Check (0x7FFFFFFFFFFFFFFFULL, "+0.499999999999999999945");
+ Check (0x8000000000000000ULL, "+0.500000000000000000000");
+ Check (0x8000000000000001ULL, "+0.500000000000000000054");
+ Check (0x8000000000000002ULL, "+0.500000000000000000108");
+ Check (0x8000000000000003ULL, "+0.500000000000000000162");
+ 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");
+
+}
+
class Int64x64CompareTestCase : public TestCase
{
public:
@@ -337,6 +424,7 @@
AddTestCase (new Int64x64ArithmeticTestCase (), TestCase::QUICK);
AddTestCase (new Int64x64Bug455TestCase (), TestCase::QUICK);
AddTestCase (new Int64x64Bug863TestCase (), TestCase::QUICK);
+ AddTestCase (new Int64x64Bug1786TestCase (), TestCase::QUICK);
AddTestCase (new Int64x64CompareTestCase (), TestCase::QUICK);
AddTestCase (new Int64x64InvertTestCase (), TestCase::QUICK);
}