serfloat_tests.cpp
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 BOOST_FIXTURE_TEST_SUITE(serfloat_tests, BasicTestingSetup) 18 19 namespace { 20 21 uint64_t TestDouble(double f) { 22 uint64_t i = EncodeDouble(f); 23 double f2 = DecodeDouble(i); 24 if (std::isnan(f)) { 25 // NaN is not guaranteed to round-trip exactly. 26 BOOST_CHECK(std::isnan(f2)); 27 } else { 28 // Everything else is. 29 BOOST_CHECK(!std::isnan(f2)); 30 uint64_t i2 = EncodeDouble(f2); 31 BOOST_CHECK_EQUAL(f, f2); 32 BOOST_CHECK_EQUAL(i, i2); 33 } 34 return i; 35 } 36 37 } // namespace 38 39 BOOST_AUTO_TEST_CASE(double_serfloat_tests) { 40 // Test specific values against their expected encoding. 41 BOOST_CHECK_EQUAL(TestDouble(0.0), 0U); 42 BOOST_CHECK_EQUAL(TestDouble(-0.0), 0x8000000000000000); 43 BOOST_CHECK_EQUAL(TestDouble(std::numeric_limits<double>::infinity()), 0x7ff0000000000000U); 44 BOOST_CHECK_EQUAL(TestDouble(-std::numeric_limits<double>::infinity()), 0xfff0000000000000); 45 BOOST_CHECK_EQUAL(TestDouble(0.5), 0x3fe0000000000000ULL); 46 BOOST_CHECK_EQUAL(TestDouble(1.0), 0x3ff0000000000000ULL); 47 BOOST_CHECK_EQUAL(TestDouble(2.0), 0x4000000000000000ULL); 48 BOOST_CHECK_EQUAL(TestDouble(4.0), 0x4010000000000000ULL); 49 BOOST_CHECK_EQUAL(TestDouble(785.066650390625), 0x4088888880000000ULL); 50 BOOST_CHECK_EQUAL(TestDouble(3.7243058682384174), 0x400dcb60e0031440); 51 BOOST_CHECK_EQUAL(TestDouble(91.64070592566159), 0x4056e901536d447a); 52 BOOST_CHECK_EQUAL(TestDouble(-98.63087668642575), 0xc058a860489c007a); 53 BOOST_CHECK_EQUAL(TestDouble(4.908737756962054), 0x4013a28c268b2b70); 54 BOOST_CHECK_EQUAL(TestDouble(77.9247330021754), 0x40537b2ed3547804); 55 BOOST_CHECK_EQUAL(TestDouble(40.24732825357566), 0x40441fa873c43dfc); 56 BOOST_CHECK_EQUAL(TestDouble(71.39395607929222), 0x4051d936938f27b6); 57 BOOST_CHECK_EQUAL(TestDouble(58.80100710817612), 0x404d668766a2bd70); 58 BOOST_CHECK_EQUAL(TestDouble(-30.10665786964975), 0xc03e1b4dee1e01b8); 59 BOOST_CHECK_EQUAL(TestDouble(60.15231509068704), 0x404e137f0f969814); 60 BOOST_CHECK_EQUAL(TestDouble(-48.15848711335961), 0xc04814494e445bc6); 61 BOOST_CHECK_EQUAL(TestDouble(26.68450101125353), 0x403aaf3b755169b0); 62 BOOST_CHECK_EQUAL(TestDouble(-65.72071986604303), 0xc0506e2046378ede); 63 BOOST_CHECK_EQUAL(TestDouble(17.95575825512381), 0x4031f4ac92b0a388); 64 BOOST_CHECK_EQUAL(TestDouble(-35.27171863226279), 0xc041a2c7ad17a42a); 65 BOOST_CHECK_EQUAL(TestDouble(-8.58810329425124), 0xc0212d1bdffef538); 66 BOOST_CHECK_EQUAL(TestDouble(88.51393044338977), 0x405620e43c83b1c8); 67 BOOST_CHECK_EQUAL(TestDouble(48.07224932612732), 0x4048093f77466ffc); 68 BOOST_CHECK_EQUAL(TestDouble(9.867348871395659e+117), 0x586f4daeb2459b9f); 69 BOOST_CHECK_EQUAL(TestDouble(-1.5166424385129721e+206), 0xeabe3bbc484bd458); 70 BOOST_CHECK_EQUAL(TestDouble(-8.585156555624594e-275), 0x8707c76eee012429); 71 BOOST_CHECK_EQUAL(TestDouble(2.2794371091628822e+113), 0x5777b2184458f4ee); 72 BOOST_CHECK_EQUAL(TestDouble(-1.1290476594131867e+163), 0xe1c91893d3488bb0); 73 BOOST_CHECK_EQUAL(TestDouble(9.143848423979275e-246), 0x0d0ff76e5f2620a3); 74 BOOST_CHECK_EQUAL(TestDouble(-2.8366718125941117e+81), 0xd0d7ec7e754b394a); 75 BOOST_CHECK_EQUAL(TestDouble(-1.2754409481684012e+229), 0xef80d32f8ec55342); 76 BOOST_CHECK_EQUAL(TestDouble(6.000577060053642e-186), 0x197a1be7c8209b6a); 77 BOOST_CHECK_EQUAL(TestDouble(2.0839423284378986e-302), 0x014c94f8689cb0a5); 78 BOOST_CHECK_EQUAL(TestDouble(-1.422140051483753e+259), 0xf5bd99271d04bb35); 79 BOOST_CHECK_EQUAL(TestDouble(-1.0593973991188853e+46), 0xc97db0cdb72d1046); 80 BOOST_CHECK_EQUAL(TestDouble(2.62945125875249e+190), 0x67779b36366c993b); 81 BOOST_CHECK_EQUAL(TestDouble(-2.920377657275094e+115), 0xd7e7b7b45908e23b); 82 BOOST_CHECK_EQUAL(TestDouble(9.790289014855851e-118), 0x27a3c031cc428bcc); 83 BOOST_CHECK_EQUAL(TestDouble(-4.629317182034961e-114), 0xa866ccf0b753705a); 84 BOOST_CHECK_EQUAL(TestDouble(-1.7674605603846528e+279), 0xf9e8ed383ffc3e25); 85 BOOST_CHECK_EQUAL(TestDouble(2.5308171727712605e+120), 0x58ef5cd55f0ec997); 86 BOOST_CHECK_EQUAL(TestDouble(-1.05034156412799e+54), 0xcb25eea1b9350fa0); 87 88 // Test extreme values 89 BOOST_CHECK_EQUAL(TestDouble(std::numeric_limits<double>::min()), 0x10000000000000); 90 BOOST_CHECK_EQUAL(TestDouble(-std::numeric_limits<double>::min()), 0x8010000000000000); 91 BOOST_CHECK_EQUAL(TestDouble(std::numeric_limits<double>::max()), 0x7fefffffffffffff); 92 BOOST_CHECK_EQUAL(TestDouble(-std::numeric_limits<double>::max()), 0xffefffffffffffff); 93 BOOST_CHECK_EQUAL(TestDouble(std::numeric_limits<double>::lowest()), 0xffefffffffffffff); 94 BOOST_CHECK_EQUAL(TestDouble(-std::numeric_limits<double>::lowest()), 0x7fefffffffffffff); 95 BOOST_CHECK_EQUAL(TestDouble(std::numeric_limits<double>::denorm_min()), 0x1); 96 BOOST_CHECK_EQUAL(TestDouble(-std::numeric_limits<double>::denorm_min()), 0x8000000000000001); 97 // Note that all NaNs are encoded the same way. 98 BOOST_CHECK_EQUAL(TestDouble(std::numeric_limits<double>::quiet_NaN()), 0x7ff8000000000000); 99 BOOST_CHECK_EQUAL(TestDouble(-std::numeric_limits<double>::quiet_NaN()), 0x7ff8000000000000); 100 BOOST_CHECK_EQUAL(TestDouble(std::numeric_limits<double>::signaling_NaN()), 0x7ff8000000000000); 101 BOOST_CHECK_EQUAL(TestDouble(-std::numeric_limits<double>::signaling_NaN()), 0x7ff8000000000000); 102 103 // Construct doubles to test from the encoding. 104 static_assert(sizeof(double) == 8); 105 static_assert(sizeof(uint64_t) == 8); 106 for (int j = 0; j < 1000; ++j) { 107 // Iterate over 9 specific bits exhaustively; the others are chosen randomly. 108 // These specific bits are the sign bit, and the 2 top and bottom bits of 109 // exponent and mantissa in the IEEE754 binary64 format. 110 for (int x = 0; x < 512; ++x) { 111 uint64_t v = InsecureRandBits(64); 112 int x_pos = 0; 113 for (int v_pos : {0, 1, 50, 51, 52, 53, 61, 62, 63}) { 114 v &= ~(uint64_t{1} << v_pos); 115 if ((x >> (x_pos++)) & 1) v |= (uint64_t{1} << v_pos); 116 } 117 double f; 118 memcpy(&f, &v, 8); 119 TestDouble(f); 120 } 121 } 122 } 123 124 /* 125 Python code to generate the below hashes: 126 127 def reversed_hex(x): 128 return bytes(reversed(x)).hex() 129 130 def dsha256(x): 131 return hashlib.sha256(hashlib.sha256(x).digest()).digest() 132 133 reversed_hex(dsha256(b''.join(struct.pack('<d', x) for x in range(0,1000)))) == '43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96' 134 */ 135 BOOST_AUTO_TEST_CASE(doubles) 136 { 137 DataStream ss{}; 138 // encode 139 for (int i = 0; i < 1000; i++) { 140 ss << EncodeDouble(i); 141 } 142 BOOST_CHECK(Hash(ss) == uint256S("43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96")); 143 144 // decode 145 for (int i = 0; i < 1000; i++) { 146 uint64_t val; 147 ss >> val; 148 double j = DecodeDouble(val); 149 BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); 150 } 151 } 152 153 BOOST_AUTO_TEST_SUITE_END()