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