Branch data Line data Source code
# 1 : : // Copyright (c) 2014-2020 The Bitcoin Core developers # 2 : : // Distributed under the MIT software license, see the accompanying # 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php. # 4 : : # 5 : : #include <hash.h> # 6 : : #include <test/util/setup_common.h> # 7 : : #include <util/serfloat.h> # 8 : : #include <serialize.h> # 9 : : #include <streams.h> # 10 : : # 11 : : #include <boost/test/unit_test.hpp> # 12 : : # 13 : : #include <cmath> # 14 : : #include <limits> # 15 : : # 16 : : BOOST_FIXTURE_TEST_SUITE(serfloat_tests, BasicTestingSetup) # 17 : : # 18 : : namespace { # 19 : : # 20 : 1024042 : uint64_t TestDouble(double f) { # 21 : 1024042 : uint64_t i = EncodeDouble(f); # 22 : 1024042 : double f2 = DecodeDouble(i); # 23 [ + + ]: 1024042 : if (std::isnan(f)) { # 24 : : // NaN is not guaranteed to round-trip exactly. # 25 : 482 : BOOST_CHECK(std::isnan(f2)); # 26 : 1023560 : } else { # 27 : : // Everything else is. # 28 : 1023560 : BOOST_CHECK(!std::isnan(f2)); # 29 : 1023560 : uint64_t i2 = EncodeDouble(f2); # 30 : 1023560 : BOOST_CHECK_EQUAL(f, f2); # 31 : 1023560 : BOOST_CHECK_EQUAL(i, i2); # 32 : 1023560 : } # 33 : 1024042 : return i; # 34 : 1024042 : } # 35 : : # 36 : : } // namespace # 37 : : # 38 : 2 : BOOST_AUTO_TEST_CASE(double_serfloat_tests) { # 39 : 2 : BOOST_CHECK_EQUAL(TestDouble(0.0), 0); # 40 : 2 : BOOST_CHECK_EQUAL(TestDouble(-0.0), 0x8000000000000000); # 41 : 2 : BOOST_CHECK_EQUAL(TestDouble(std::numeric_limits<double>::infinity()), 0x7ff0000000000000); # 42 : 2 : BOOST_CHECK_EQUAL(TestDouble(-std::numeric_limits<double>::infinity()), 0xfff0000000000000); # 43 : 2 : BOOST_CHECK_EQUAL(TestDouble(0.5), 0x3fe0000000000000ULL); # 44 : 2 : BOOST_CHECK_EQUAL(TestDouble(1.0), 0x3ff0000000000000ULL); # 45 : 2 : BOOST_CHECK_EQUAL(TestDouble(2.0), 0x4000000000000000ULL); # 46 : 2 : BOOST_CHECK_EQUAL(TestDouble(4.0), 0x4010000000000000ULL); # 47 : 2 : BOOST_CHECK_EQUAL(TestDouble(785.066650390625), 0x4088888880000000ULL); # 48 : : # 49 : : // Roundtrip test on IEC559-compatible systems # 50 : 2 : if (std::numeric_limits<double>::is_iec559) { # 51 : 2 : BOOST_CHECK_EQUAL(sizeof(double), 8); # 52 : 2 : BOOST_CHECK_EQUAL(sizeof(uint64_t), 8); # 53 : : // Test extreme values # 54 : 2 : TestDouble(std::numeric_limits<double>::min()); # 55 : 2 : TestDouble(-std::numeric_limits<double>::min()); # 56 : 2 : TestDouble(std::numeric_limits<double>::max()); # 57 : 2 : TestDouble(-std::numeric_limits<double>::max()); # 58 : 2 : TestDouble(std::numeric_limits<double>::lowest()); # 59 : 2 : TestDouble(-std::numeric_limits<double>::lowest()); # 60 : 2 : TestDouble(std::numeric_limits<double>::quiet_NaN()); # 61 : 2 : TestDouble(-std::numeric_limits<double>::quiet_NaN()); # 62 : 2 : TestDouble(std::numeric_limits<double>::signaling_NaN()); # 63 : 2 : TestDouble(-std::numeric_limits<double>::signaling_NaN()); # 64 : 2 : TestDouble(std::numeric_limits<double>::denorm_min()); # 65 : 2 : TestDouble(-std::numeric_limits<double>::denorm_min()); # 66 : : // Test exact encoding: on currently supported platforms, EncodeDouble # 67 : : // should produce exactly the same as the in-memory representation for non-NaN. # 68 [ + + ]: 2002 : for (int j = 0; j < 1000; ++j) { # 69 : : // Iterate over 9 specific bits exhaustively; the others are chosen randomly. # 70 : : // These specific bits are the sign bit, and the 2 top and bottom bits of # 71 : : // exponent and mantissa in the IEEE754 binary64 format. # 72 [ + + ]: 1026000 : for (int x = 0; x < 512; ++x) { # 73 : 1024000 : uint64_t v = InsecureRandBits(64); # 74 : 1024000 : v &= ~(uint64_t{1} << 0); # 75 [ + + ]: 1024000 : if (x & 1) v |= (uint64_t{1} << 0); # 76 : 1024000 : v &= ~(uint64_t{1} << 1); # 77 [ + + ]: 1024000 : if (x & 2) v |= (uint64_t{1} << 1); # 78 : 1024000 : v &= ~(uint64_t{1} << 50); # 79 [ + + ]: 1024000 : if (x & 4) v |= (uint64_t{1} << 50); # 80 : 1024000 : v &= ~(uint64_t{1} << 51); # 81 [ + + ]: 1024000 : if (x & 8) v |= (uint64_t{1} << 51); # 82 : 1024000 : v &= ~(uint64_t{1} << 52); # 83 [ + + ]: 1024000 : if (x & 16) v |= (uint64_t{1} << 52); # 84 : 1024000 : v &= ~(uint64_t{1} << 53); # 85 [ + + ]: 1024000 : if (x & 32) v |= (uint64_t{1} << 53); # 86 : 1024000 : v &= ~(uint64_t{1} << 61); # 87 [ + + ]: 1024000 : if (x & 64) v |= (uint64_t{1} << 61); # 88 : 1024000 : v &= ~(uint64_t{1} << 62); # 89 [ + + ]: 1024000 : if (x & 128) v |= (uint64_t{1} << 62); # 90 : 1024000 : v &= ~(uint64_t{1} << 63); # 91 [ + + ]: 1024000 : if (x & 256) v |= (uint64_t{1} << 63); # 92 : 1024000 : double f; # 93 : 1024000 : memcpy(&f, &v, 8); # 94 : 1024000 : uint64_t v2 = TestDouble(f); # 95 [ + + ]: 1024000 : if (!std::isnan(f)) BOOST_CHECK_EQUAL(v, v2); # 96 : 1024000 : } # 97 : 2000 : } # 98 : 2 : } # 99 : 2 : } # 100 : : # 101 : : /* # 102 : : Python code to generate the below hashes: # 103 : : # 104 : : def reversed_hex(x): # 105 : : return binascii.hexlify(''.join(reversed(x))) # 106 : : def dsha256(x): # 107 : : return hashlib.sha256(hashlib.sha256(x).digest()).digest() # 108 : : # 109 : : reversed_hex(dsha256(''.join(struct.pack('<d', x) for x in range(0,1000)))) == '43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96' # 110 : : */ # 111 : : BOOST_AUTO_TEST_CASE(doubles) # 112 : 2 : { # 113 : 2 : CDataStream ss(SER_DISK, 0); # 114 : : // encode # 115 [ + + ]: 2002 : for (int i = 0; i < 1000; i++) { # 116 : 2000 : ss << EncodeDouble(i); # 117 : 2000 : } # 118 : 2 : BOOST_CHECK(Hash(ss) == uint256S("43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96")); # 119 : : # 120 : : // decode # 121 [ + + ]: 2002 : for (int i = 0; i < 1000; i++) { # 122 : 2000 : uint64_t val; # 123 : 2000 : ss >> val; # 124 : 2000 : double j = DecodeDouble(val); # 125 : 2000 : BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); # 126 : 2000 : } # 127 : 2 : } # 128 : : # 129 : : BOOST_AUTO_TEST_SUITE_END()