[Bug 1786] os << int64x64_t prints un-normalized fractional values
This commit is contained in:
@@ -14,34 +14,13 @@ NS_LOG_COMPONENT_DEFINE ("int64x64");
|
||||
|
||||
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 @@ std::ostream &operator << (std::ostream &os, const int64x64_t &value)
|
||||
}
|
||||
}
|
||||
|
||||
os << hi << ".";
|
||||
os.flags (ff); // Restore stream flags
|
||||
os << std::right << hi << ".";
|
||||
|
||||
uint64_t low = value.GetLow ();
|
||||
uint8_t msd = MostSignificantDigit (~((uint64_t)0));
|
||||
do
|
||||
os << std::noshowpos;
|
||||
|
||||
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 @@ static uint64_t ReadDigits (std::string str)
|
||||
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 @@ std::istream &operator >> (std::istream &is, int64x64_t &value)
|
||||
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;
|
||||
|
||||
@@ -79,6 +79,18 @@ INT64X64_OP_CMP (<=)
|
||||
INT64X64_OP_CMP (>)
|
||||
INT64X64_OP_CMP (>=)
|
||||
|
||||
/**
|
||||
* Output streamer for int64x64_t
|
||||
*
|
||||
* Values are printed with the following format flags
|
||||
* independent of the the stream flags):
|
||||
* - `showpos`
|
||||
* - `left`
|
||||
* The stream `width` is ignored. If `floatfield` is set,
|
||||
* `precision` decimal places are printed. If `floatfield` is not set,
|
||||
* all digits of the fractional part are printed, up to the
|
||||
* representation limit of 20 digits; trailing zeros are omitted.
|
||||
*/
|
||||
std::ostream &operator << (std::ostream &os, const int64x64_t &val);
|
||||
std::istream &operator >> (std::istream &is, int64x64_t &val);
|
||||
|
||||
|
||||
@@ -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 @@ Int64x64InputTestCase::DoRun (void)
|
||||
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 @@ Int64x64InputOutputTestCase::CheckString (std::string str)
|
||||
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 @@ Int64x64Bug863TestCase::DoRun (void)
|
||||
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 @@ public:
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user