1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 22:37:35 +00:00

LibCrypto: Add a rounding mode to UnsignedBigInteger::to_double

This allows using different options for rounding, like IEEE
roundTiesToEven, which is the mode that JS requires.

Also fix that the last word read from the bigint for the mantissa could
be shifted incorrectly leading to incorrect results.
This commit is contained in:
davidot 2022-08-25 17:56:34 +02:00 committed by Linus Groh
parent 8ba6e96d05
commit 77d71a5ffd
5 changed files with 144 additions and 24 deletions

View file

@ -750,7 +750,7 @@ EXPECT_EQUAL_TO(zero, -0.0);
TEST_CASE(to_double)
{
#define EXPECT_TO_EQUAL_DOUBLE(bigint, double_value) \
EXPECT_EQ((bigint).to_double(), double_value)
EXPECT_EQ((bigint).to_double(Crypto::UnsignedBigInteger::RoundingMode::RoundTowardZero), double_value)
EXPECT_TO_EQUAL_DOUBLE(Crypto::UnsignedBigInteger(0), 0.0);
// Make sure we don't get negative zero!
@ -825,7 +825,41 @@ TEST_CASE(to_double)
EXPECT_TO_EQUAL_DOUBLE(Crypto::SignedBigInteger::from_base(10, "2345678901234567890"sv),
2345678901234567680.0);
EXPECT_EQ(1234567890123456800.0, 1234567890123456768.0);
EXPECT_EQ(
Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
2305843009213693696.0);
EXPECT_EQ(
Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::RoundTowardZero),
2305843009213693696.0);
EXPECT_EQ(
Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff80"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
2305843009213693952.0);
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000001"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
9007199254740992.0);
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000002"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
9007199254740994.0);
// 2^53 = 20000000000000, +3 Rounds up because of tiesRoundToEven
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000003"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
9007199254740996.0);
// +4 is exactly 9007199254740996
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000004"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
9007199254740996.0);
// +5 rounds down because of tiesRoundToEven
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000005"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
9007199254740996.0);
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000006"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
9007199254740998.0);
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(10, "98382635059784269824"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
bit_cast<double>(0x4415555555555555ULL));
#undef EXPECT_TO_EQUAL_DOUBLE
}