1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 02:37:36 +00:00

LibCrypto: Add a way to compare UnsignedBigInteger with double

This patch also make SignedBigInteger::compare_to_double make use
of the new function.
This commit is contained in:
Moustafa Raafat 2022-10-23 16:46:35 +01:00 committed by Andrew Kaster
parent e03f014e7a
commit 54b8a2b094
7 changed files with 259 additions and 158 deletions

View file

@ -660,9 +660,9 @@ TEST_CASE(test_negative_zero_is_not_allowed)
}
TEST_CASE(double_comparisons) {
#define EXPECT_LESS_THAN(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::SignedBigInteger::CompareResult::DoubleGreaterThanBigInt)
#define EXPECT_GREATER_THAN(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::SignedBigInteger::CompareResult::DoubleLessThanBigInt)
#define EXPECT_EQUAL_TO(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::SignedBigInteger::CompareResult::DoubleEqualsBigInt)
#define EXPECT_LESS_THAN(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleGreaterThanBigInt)
#define EXPECT_GREATER_THAN(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleLessThanBigInt)
#define EXPECT_EQUAL_TO(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleEqualsBigInt)
{ Crypto::SignedBigInteger zero { 0 };
EXPECT_EQUAL_TO(zero, 0.0);
EXPECT_EQUAL_TO(zero, -0.0);
@ -687,6 +687,14 @@ EXPECT_EQUAL_TO(zero, -0.0);
EXPECT_GREATER_THAN(one, -1.000001);
}
{
double double_infinity = HUGE_VAL;
VERIFY(isinf(double_infinity));
Crypto::SignedBigInteger one { 1 };
EXPECT_LESS_THAN(one, double_infinity);
EXPECT_GREATER_THAN(one, -double_infinity);
}
{
double double_max_value = NumericLimits<double>::max();
double double_below_max_value = nextafter(double_max_value, 0.0);
@ -938,18 +946,86 @@ TEST_CASE(bigint_from_double)
#undef SURVIVES_ROUND_TRIP_SIGNED
#undef SURVIVES_ROUND_TRIP_UNSIGNED
}
TEST_CASE(unsigned_bigint_double_comparisons)
{
#define EXPECT_LESS_THAN(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleGreaterThanBigInt)
#define EXPECT_GREATER_THAN(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleLessThanBigInt)
#define EXPECT_EQUAL_TO(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleEqualsBigInt)
{
Crypto::UnsignedBigInteger zero { 0 };
EXPECT_EQUAL_TO(zero, 0.0);
EXPECT_EQUAL_TO(zero, -0.0);
}
{
Crypto::UnsignedBigInteger one { 1 };
EXPECT_EQUAL_TO(one, 1.0);
EXPECT_GREATER_THAN(one, -1.0);
EXPECT_GREATER_THAN(one, 0.5);
EXPECT_GREATER_THAN(one, -0.5);
EXPECT_LESS_THAN(one, 1.000001);
}
{
double double_infinity = HUGE_VAL;
VERIFY(isinf(double_infinity));
Crypto::UnsignedBigInteger one { 1 };
EXPECT_LESS_THAN(one, double_infinity);
EXPECT_GREATER_THAN(one, -double_infinity);
}
{
double double_max_value = NumericLimits<double>::max();
double double_below_max_value = nextafter(double_max_value, 0.0);
VERIFY(double_below_max_value < double_max_value);
VERIFY(double_below_max_value < (double_max_value - 1.0));
auto max_value_in_bigint = Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv);
auto max_value_plus_one = max_value_in_bigint.plus(Crypto::UnsignedBigInteger { 1 });
auto max_value_minus_one = max_value_in_bigint.minus(Crypto::UnsignedBigInteger { 1 });
auto below_max_value_in_bigint = Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv);
EXPECT_EQUAL_TO(max_value_in_bigint, double_max_value);
EXPECT_LESS_THAN(max_value_minus_one, double_max_value);
EXPECT_GREATER_THAN(max_value_plus_one, double_max_value);
EXPECT_LESS_THAN(below_max_value_in_bigint, double_max_value);
EXPECT_GREATER_THAN(max_value_in_bigint, double_below_max_value);
EXPECT_GREATER_THAN(max_value_minus_one, double_below_max_value);
EXPECT_GREATER_THAN(max_value_plus_one, double_below_max_value);
EXPECT_EQUAL_TO(below_max_value_in_bigint, double_below_max_value);
}
{
double just_above_255 = bit_cast<double>(0x406fe00000000001ULL);
double just_below_255 = bit_cast<double>(0x406fdfffffffffffULL);
double double_255 = 255.0;
Crypto::UnsignedBigInteger bigint_255 { 255 };
EXPECT_EQUAL_TO(bigint_255, double_255);
EXPECT_GREATER_THAN(bigint_255, just_below_255);
EXPECT_LESS_THAN(bigint_255, just_above_255);
}
#undef EXPECT_LESS_THAN
#undef EXPECT_GREATER_THAN
#undef EXPECT_EQUAL_TO
}
namespace AK {
template<>
struct Formatter<Crypto::SignedBigInteger::CompareResult> : Formatter<StringView> {
ErrorOr<void> format(FormatBuilder& builder, Crypto::SignedBigInteger::CompareResult const& compare_result)
struct Formatter<Crypto::UnsignedBigInteger::CompareResult> : Formatter<StringView> {
ErrorOr<void> format(FormatBuilder& builder, Crypto::UnsignedBigInteger::CompareResult const& compare_result)
{
switch (compare_result) {
case Crypto::SignedBigInteger::CompareResult::DoubleEqualsBigInt:
case Crypto::UnsignedBigInteger::CompareResult::DoubleEqualsBigInt:
return builder.put_string("Equals"sv);
case Crypto::SignedBigInteger::CompareResult::DoubleLessThanBigInt:
case Crypto::UnsignedBigInteger::CompareResult::DoubleLessThanBigInt:
return builder.put_string("LessThan"sv);
case Crypto::SignedBigInteger::CompareResult::DoubleGreaterThanBigInt:
case Crypto::UnsignedBigInteger::CompareResult::DoubleGreaterThanBigInt:
return builder.put_string("GreaterThan"sv);
default:
return builder.put_string("???"sv);