Skip to content

Commit 479ecc0

Browse files
committed
Merge bitcoin#29192: Weaken serfloat tests
6e873df serfloat: improve/simplify tests (Pieter Wuille) b45f1f5 serfloat: do not test encode(bits)=bits anymore (Pieter Wuille) Pull request description: Closes bitcoin#28941. Our current tests for serfloat verify two distinct properties: 1. Whether they roundtrip `double`->`uint64_t`->`double` (excluding NaN values) on all systems. 2. Whether on systems with a typical floating point unit that encoding matches the hardware representation, as before v22.0, we would dump the hardware representation directly to disk and we wanted to retain compatibility with that. bitcoin#28941 seems to show that the second property doesn't always hold, but just for "subnormal" numbers (below $2^{-1021}$). Since we don't care about encoding these numbers, we could exclude such subnormal numbers from the hardware-identical representation test, but this PR goes further and just drops the second property entirely, as I don't think we care about edge-case compatibility with pre-v22.0 code for fee_estimates.dat (the only place it is used). ACKs for top commit: glozow: ACK 6e873df fanquake: ACK 6e873df - It's not as much of a priority, but I think we could still backport this. Tree-SHA512: e18ceee0753a7ee7e999fdfa10b014dc5bb67b6ef79522a0f8c76b889adcfa785772fc26ed7559bcb5a09a9938e243bb54eedd9549bc59080a2c8090155e2267
2 parents 8e95a9c + 6e873df commit 479ecc0

File tree

1 file changed

+69
-47
lines changed

1 file changed

+69
-47
lines changed

src/test/serfloat_tests.cpp

Lines changed: 69 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ uint64_t TestDouble(double f) {
3737
} // namespace
3838

3939
BOOST_AUTO_TEST_CASE(double_serfloat_tests) {
40+
// Test specific values against their expected encoding.
4041
BOOST_CHECK_EQUAL(TestDouble(0.0), 0U);
4142
BOOST_CHECK_EQUAL(TestDouble(-0.0), 0x8000000000000000);
4243
BOOST_CHECK_EQUAL(TestDouble(std::numeric_limits<double>::infinity()), 0x7ff0000000000000U);
@@ -46,55 +47,76 @@ BOOST_AUTO_TEST_CASE(double_serfloat_tests) {
4647
BOOST_CHECK_EQUAL(TestDouble(2.0), 0x4000000000000000ULL);
4748
BOOST_CHECK_EQUAL(TestDouble(4.0), 0x4010000000000000ULL);
4849
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);
4987

50-
// Roundtrip test on IEC559-compatible systems
51-
if (std::numeric_limits<double>::is_iec559) {
52-
BOOST_CHECK_EQUAL(sizeof(double), 8U);
53-
BOOST_CHECK_EQUAL(sizeof(uint64_t), 8U);
54-
// Test extreme values
55-
TestDouble(std::numeric_limits<double>::min());
56-
TestDouble(-std::numeric_limits<double>::min());
57-
TestDouble(std::numeric_limits<double>::max());
58-
TestDouble(-std::numeric_limits<double>::max());
59-
TestDouble(std::numeric_limits<double>::lowest());
60-
TestDouble(-std::numeric_limits<double>::lowest());
61-
TestDouble(std::numeric_limits<double>::quiet_NaN());
62-
TestDouble(-std::numeric_limits<double>::quiet_NaN());
63-
TestDouble(std::numeric_limits<double>::signaling_NaN());
64-
TestDouble(-std::numeric_limits<double>::signaling_NaN());
65-
TestDouble(std::numeric_limits<double>::denorm_min());
66-
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-
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-
for (int x = 0; x < 512; ++x) {
74-
uint64_t v = InsecureRandBits(64);
75-
v &= ~(uint64_t{1} << 0);
76-
if (x & 1) v |= (uint64_t{1} << 0);
77-
v &= ~(uint64_t{1} << 1);
78-
if (x & 2) v |= (uint64_t{1} << 1);
79-
v &= ~(uint64_t{1} << 50);
80-
if (x & 4) v |= (uint64_t{1} << 50);
81-
v &= ~(uint64_t{1} << 51);
82-
if (x & 8) v |= (uint64_t{1} << 51);
83-
v &= ~(uint64_t{1} << 52);
84-
if (x & 16) v |= (uint64_t{1} << 52);
85-
v &= ~(uint64_t{1} << 53);
86-
if (x & 32) v |= (uint64_t{1} << 53);
87-
v &= ~(uint64_t{1} << 61);
88-
if (x & 64) v |= (uint64_t{1} << 61);
89-
v &= ~(uint64_t{1} << 62);
90-
if (x & 128) v |= (uint64_t{1} << 62);
91-
v &= ~(uint64_t{1} << 63);
92-
if (x & 256) v |= (uint64_t{1} << 63);
93-
double f;
94-
memcpy(&f, &v, 8);
95-
uint64_t v2 = TestDouble(f);
96-
if (!std::isnan(f)) BOOST_CHECK_EQUAL(v, v2);
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);
97116
}
117+
double f;
118+
memcpy(&f, &v, 8);
119+
TestDouble(f);
98120
}
99121
}
100122
}

0 commit comments

Comments
 (0)