LibCrypto: Make constructing a BigInteger from string fallible
Previously, constructing a `UnsignedBigInteger::from_base()` could produce an incorrect result if the input string contained a valid Base36 digit that was out of range of the given base. The same method would also crash if the input string contained an invalid Base36 digit. An error is now returned in both these cases. Constructing a BigFraction from string is now also fallible, so that we can handle the case where we are given an input string with invalid digits.
This commit is contained in:
parent
0b0c7693e2
commit
48a3a02238
Notes:
sideshowbarker
2024-07-17 05:18:58 +09:00
Author: https://github.com/tcl3 Commit: https://github.com/SerenityOS/serenity/commit/48a3a02238 Pull-request: https://github.com/SerenityOS/serenity/pull/22726 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/LucasChollet ✅
11 changed files with 68 additions and 57 deletions
|
@ -234,9 +234,13 @@ TEST_CASE(test_unsigned_bigint_division_combined_test)
|
||||||
|
|
||||||
TEST_CASE(test_unsigned_bigint_base10_from_string)
|
TEST_CASE(test_unsigned_bigint_base10_from_string)
|
||||||
{
|
{
|
||||||
auto result = Crypto::UnsignedBigInteger::from_base(10, "57195071295721390579057195715793"sv);
|
auto result = TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(10, "57195071295721390579057195715793"sv));
|
||||||
Vector<u32> expected_result { 3806301393, 954919431, 3879607298, 721 };
|
Vector<u32> expected_result { 3806301393, 954919431, 3879607298, 721 };
|
||||||
EXPECT_EQ(result.words(), expected_result);
|
EXPECT_EQ(result.words(), expected_result);
|
||||||
|
|
||||||
|
Vector<StringView> invalid_base10_number_strings { "1A"sv, "1:"sv, "Z1"sv, "1/"sv };
|
||||||
|
for (auto invalid_base10_number_string : invalid_base10_number_strings)
|
||||||
|
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(10, invalid_base10_number_string).is_error(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(test_unsigned_bigint_base10_to_string)
|
TEST_CASE(test_unsigned_bigint_base10_to_string)
|
||||||
|
@ -701,11 +705,11 @@ EXPECT_EQUAL_TO(zero, -0.0);
|
||||||
double double_below_max_value = nextafter(double_max_value, 0.0);
|
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);
|
||||||
VERIFY(double_below_max_value < (double_max_value - 1.0));
|
VERIFY(double_below_max_value < (double_max_value - 1.0));
|
||||||
auto max_value_in_bigint = Crypto::SignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv);
|
auto max_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv));
|
||||||
auto max_value_plus_one = max_value_in_bigint.plus(Crypto::SignedBigInteger { 1 });
|
auto max_value_plus_one = max_value_in_bigint.plus(Crypto::SignedBigInteger { 1 });
|
||||||
auto max_value_minus_one = max_value_in_bigint.minus(Crypto::SignedBigInteger { 1 });
|
auto max_value_minus_one = max_value_in_bigint.minus(Crypto::SignedBigInteger { 1 });
|
||||||
|
|
||||||
auto below_max_value_in_bigint = Crypto::SignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv);
|
auto below_max_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv));
|
||||||
|
|
||||||
EXPECT_EQUAL_TO(max_value_in_bigint, double_max_value);
|
EXPECT_EQUAL_TO(max_value_in_bigint, double_max_value);
|
||||||
EXPECT_LESS_THAN(max_value_minus_one, double_max_value);
|
EXPECT_LESS_THAN(max_value_minus_one, double_max_value);
|
||||||
|
@ -723,11 +727,11 @@ EXPECT_EQUAL_TO(zero, -0.0);
|
||||||
double double_above_min_value = nextafter(double_min_value, 0.0);
|
double double_above_min_value = nextafter(double_min_value, 0.0);
|
||||||
VERIFY(double_above_min_value > double_min_value);
|
VERIFY(double_above_min_value > double_min_value);
|
||||||
VERIFY(double_above_min_value > (double_min_value + 1.0));
|
VERIFY(double_above_min_value > (double_min_value + 1.0));
|
||||||
auto min_value_in_bigint = Crypto::SignedBigInteger::from_base(16, "-fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv);
|
auto min_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv));
|
||||||
auto min_value_plus_one = min_value_in_bigint.plus(Crypto::SignedBigInteger { 1 });
|
auto min_value_plus_one = min_value_in_bigint.plus(Crypto::SignedBigInteger { 1 });
|
||||||
auto min_value_minus_one = min_value_in_bigint.minus(Crypto::SignedBigInteger { 1 });
|
auto min_value_minus_one = min_value_in_bigint.minus(Crypto::SignedBigInteger { 1 });
|
||||||
|
|
||||||
auto above_min_value_in_bigint = Crypto::SignedBigInteger::from_base(16, "-fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv);
|
auto above_min_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv));
|
||||||
|
|
||||||
EXPECT_EQUAL_TO(min_value_in_bigint, double_min_value);
|
EXPECT_EQUAL_TO(min_value_in_bigint, double_min_value);
|
||||||
EXPECT_LESS_THAN(min_value_minus_one, double_min_value);
|
EXPECT_LESS_THAN(min_value_minus_one, double_min_value);
|
||||||
|
@ -785,89 +789,89 @@ TEST_CASE(to_double)
|
||||||
double infinity = INFINITY;
|
double infinity = INFINITY;
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(
|
EXPECT_TO_EQUAL_DOUBLE(
|
||||||
Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv),
|
TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)),
|
||||||
double_max_value);
|
double_max_value);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(
|
EXPECT_TO_EQUAL_DOUBLE(
|
||||||
Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv),
|
TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)),
|
||||||
double_max_value);
|
double_max_value);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(
|
EXPECT_TO_EQUAL_DOUBLE(
|
||||||
Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"sv),
|
TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"sv)),
|
||||||
double_max_value);
|
double_max_value);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(
|
EXPECT_TO_EQUAL_DOUBLE(
|
||||||
Crypto::UnsignedBigInteger::from_base(16, "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv),
|
TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)),
|
||||||
infinity);
|
infinity);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(
|
EXPECT_TO_EQUAL_DOUBLE(
|
||||||
Crypto::SignedBigInteger::from_base(16, "-fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv),
|
TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)),
|
||||||
-double_max_value);
|
-double_max_value);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(
|
EXPECT_TO_EQUAL_DOUBLE(
|
||||||
Crypto::SignedBigInteger::from_base(16, "-ffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv),
|
TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-ffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)),
|
||||||
-double_max_value);
|
-double_max_value);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(
|
EXPECT_TO_EQUAL_DOUBLE(
|
||||||
Crypto::SignedBigInteger::from_base(16, "-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"sv),
|
TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"sv)),
|
||||||
-double_max_value);
|
-double_max_value);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(
|
EXPECT_TO_EQUAL_DOUBLE(
|
||||||
Crypto::SignedBigInteger::from_base(16, "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv),
|
TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)),
|
||||||
-infinity);
|
-infinity);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(
|
EXPECT_TO_EQUAL_DOUBLE(
|
||||||
Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffffff"sv),
|
TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffffff"sv)),
|
||||||
18446744073709549568.0);
|
18446744073709549568.0);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(
|
EXPECT_TO_EQUAL_DOUBLE(
|
||||||
Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800"sv),
|
TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800"sv)),
|
||||||
18446744073709549568.0);
|
18446744073709549568.0);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(
|
EXPECT_TO_EQUAL_DOUBLE(
|
||||||
Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff8ff"sv),
|
TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff8ff"sv)),
|
||||||
18446744073709549568.0);
|
18446744073709549568.0);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(Crypto::SignedBigInteger::from_base(10, "1234567890123456789"sv),
|
EXPECT_TO_EQUAL_DOUBLE(TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(10, "1234567890123456789"sv)),
|
||||||
1234567890123456800.0);
|
1234567890123456800.0);
|
||||||
|
|
||||||
EXPECT_TO_EQUAL_DOUBLE(Crypto::SignedBigInteger::from_base(10, "2345678901234567890"sv),
|
EXPECT_TO_EQUAL_DOUBLE(TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(10, "2345678901234567890"sv)),
|
||||||
2345678901234567680.0);
|
2345678901234567680.0);
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
||||||
2305843009213693696.0);
|
2305843009213693696.0);
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::RoundTowardZero),
|
TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::RoundTowardZero),
|
||||||
2305843009213693696.0);
|
2305843009213693696.0);
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff80"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff80"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
||||||
2305843009213693952.0);
|
2305843009213693952.0);
|
||||||
|
|
||||||
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000001"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000001"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
||||||
9007199254740992.0);
|
9007199254740992.0);
|
||||||
|
|
||||||
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000002"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000002"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
||||||
9007199254740994.0);
|
9007199254740994.0);
|
||||||
|
|
||||||
// 2^53 = 20000000000000, +3 Rounds up because of tiesRoundToEven
|
// 2^53 = 20000000000000, +3 Rounds up because of tiesRoundToEven
|
||||||
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000003"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000003"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
||||||
9007199254740996.0);
|
9007199254740996.0);
|
||||||
|
|
||||||
// +4 is exactly 9007199254740996
|
// +4 is exactly 9007199254740996
|
||||||
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000004"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000004"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
||||||
9007199254740996.0);
|
9007199254740996.0);
|
||||||
|
|
||||||
// +5 rounds down because of tiesRoundToEven
|
// +5 rounds down because of tiesRoundToEven
|
||||||
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000005"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000005"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
||||||
9007199254740996.0);
|
9007199254740996.0);
|
||||||
|
|
||||||
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000006"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000006"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
||||||
9007199254740998.0);
|
9007199254740998.0);
|
||||||
|
|
||||||
EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(10, "98382635059784269824"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(10, "98382635059784269824"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa),
|
||||||
bit_cast<double>(0x4415555555555555ULL));
|
bit_cast<double>(0x4415555555555555ULL));
|
||||||
|
|
||||||
#undef EXPECT_TO_EQUAL_DOUBLE
|
#undef EXPECT_TO_EQUAL_DOUBLE
|
||||||
|
@ -982,11 +986,11 @@ TEST_CASE(unsigned_bigint_double_comparisons)
|
||||||
double double_below_max_value = nextafter(double_max_value, 0.0);
|
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);
|
||||||
VERIFY(double_below_max_value < (double_max_value - 1.0));
|
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_in_bigint = TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv));
|
||||||
auto max_value_plus_one = max_value_in_bigint.plus(Crypto::UnsignedBigInteger { 1 });
|
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 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);
|
auto below_max_value_in_bigint = TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv));
|
||||||
|
|
||||||
EXPECT_EQUAL_TO(max_value_in_bigint, double_max_value);
|
EXPECT_EQUAL_TO(max_value_in_bigint, double_max_value);
|
||||||
EXPECT_LESS_THAN(max_value_minus_one, double_max_value);
|
EXPECT_LESS_THAN(max_value_minus_one, double_max_value);
|
||||||
|
|
|
@ -59,8 +59,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
auto clipboard = GUI::Clipboard::the().fetch_data_and_type();
|
auto clipboard = GUI::Clipboard::the().fetch_data_and_type();
|
||||||
if (clipboard.mime_type == "text/plain") {
|
if (clipboard.mime_type == "text/plain") {
|
||||||
if (!clipboard.data.is_empty()) {
|
if (!clipboard.data.is_empty()) {
|
||||||
auto const number = StringView(clipboard.data);
|
auto number_or_error = Crypto::BigFraction::from_string(StringView(clipboard.data));
|
||||||
widget->set_typed_entry(Crypto::BigFraction(number));
|
if (!number_or_error.is_error())
|
||||||
|
widget->set_typed_entry(number_or_error.release_value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -25,20 +25,18 @@ BigFraction::BigFraction(SignedBigInteger value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
BigFraction::BigFraction(StringView sv)
|
ErrorOr<BigFraction> BigFraction::from_string(StringView sv)
|
||||||
{
|
{
|
||||||
// FIXME: This constructor is definitely fallible, errors should also be propagated
|
|
||||||
// from both signed and unsigned version of from_base.
|
|
||||||
auto maybe_dot_index = sv.find('.');
|
auto maybe_dot_index = sv.find('.');
|
||||||
|
|
||||||
auto integer_part_view = sv.substring_view(0, maybe_dot_index.value_or(sv.length()));
|
auto integer_part_view = sv.substring_view(0, maybe_dot_index.value_or(sv.length()));
|
||||||
auto fraction_part_view = maybe_dot_index.has_value() ? sv.substring_view(1 + *maybe_dot_index) : "0"sv;
|
auto fraction_part_view = maybe_dot_index.has_value() ? sv.substring_view(1 + *maybe_dot_index) : "0"sv;
|
||||||
|
|
||||||
auto integer_part = SignedBigInteger::from_base(10, integer_part_view);
|
auto integer_part = TRY(SignedBigInteger::from_base(10, integer_part_view));
|
||||||
auto fractional_part = SignedBigInteger::from_base(10, fraction_part_view);
|
auto fractional_part = TRY(SignedBigInteger::from_base(10, fraction_part_view));
|
||||||
auto fraction_length = UnsignedBigInteger(static_cast<u64>(fraction_part_view.length()));
|
auto fraction_length = UnsignedBigInteger(static_cast<u64>(fraction_part_view.length()));
|
||||||
|
|
||||||
*this = BigFraction(move(integer_part)) + BigFraction(move(fractional_part), NumberTheory::Power("10"_bigint, move(fraction_length)));
|
return BigFraction(move(integer_part)) + BigFraction(move(fractional_part), NumberTheory::Power("10"_bigint, move(fraction_length)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BigFraction BigFraction::operator+(BigFraction const& rhs) const
|
BigFraction BigFraction::operator+(BigFraction const& rhs) const
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Crypto {
|
||||||
class BigFraction {
|
class BigFraction {
|
||||||
// FIXME Make the whole API more error-friendly. This includes:
|
// FIXME Make the whole API more error-friendly. This includes:
|
||||||
// - Propagating errors from BigIntegers
|
// - Propagating errors from BigIntegers
|
||||||
// - Returns errors from both BigFraction(StringView) and BigFraction(numerator, denominator);
|
// - Returns errors from BigFraction(numerator, denominator);
|
||||||
// - Duplicate fallible operators with a error-friendly version
|
// - Duplicate fallible operators with a error-friendly version
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -27,9 +27,10 @@ public:
|
||||||
BigFraction& operator=(Crypto::BigFraction const&) = default;
|
BigFraction& operator=(Crypto::BigFraction const&) = default;
|
||||||
BigFraction& operator=(Crypto::BigFraction&&) = default;
|
BigFraction& operator=(Crypto::BigFraction&&) = default;
|
||||||
|
|
||||||
explicit BigFraction(StringView);
|
|
||||||
explicit BigFraction(double);
|
explicit BigFraction(double);
|
||||||
|
|
||||||
|
static ErrorOr<BigFraction> from_string(StringView);
|
||||||
|
|
||||||
BigFraction operator+(BigFraction const&) const;
|
BigFraction operator+(BigFraction const&) const;
|
||||||
BigFraction operator-(BigFraction const&) const;
|
BigFraction operator-(BigFraction const&) const;
|
||||||
BigFraction operator*(BigFraction const&) const;
|
BigFraction operator*(BigFraction const&) const;
|
||||||
|
|
|
@ -35,7 +35,7 @@ size_t SignedBigInteger::export_data(Bytes data, bool remove_leading_zeros) cons
|
||||||
return m_unsigned_data.export_data(bytes_view, remove_leading_zeros) + 1;
|
return m_unsigned_data.export_data(bytes_view, remove_leading_zeros) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SignedBigInteger SignedBigInteger::from_base(u16 N, StringView str)
|
ErrorOr<SignedBigInteger> SignedBigInteger::from_base(u16 N, StringView str)
|
||||||
{
|
{
|
||||||
auto sign = false;
|
auto sign = false;
|
||||||
if (str.length() > 1) {
|
if (str.length() > 1) {
|
||||||
|
@ -47,8 +47,8 @@ SignedBigInteger SignedBigInteger::from_base(u16 N, StringView str)
|
||||||
if (maybe_sign == '+')
|
if (maybe_sign == '+')
|
||||||
str = str.substring_view(1);
|
str = str.substring_view(1);
|
||||||
}
|
}
|
||||||
auto unsigned_data = UnsignedBigInteger::from_base(N, str);
|
auto unsigned_data = TRY(UnsignedBigInteger::from_base(N, str));
|
||||||
return { move(unsigned_data), sign };
|
return SignedBigInteger { move(unsigned_data), sign };
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<String> SignedBigInteger::to_base(u16 N) const
|
ErrorOr<String> SignedBigInteger::to_base(u16 N) const
|
||||||
|
|
|
@ -63,7 +63,7 @@ public:
|
||||||
|
|
||||||
size_t export_data(Bytes, bool remove_leading_zeros = false) const;
|
size_t export_data(Bytes, bool remove_leading_zeros = false) const;
|
||||||
|
|
||||||
[[nodiscard]] static SignedBigInteger from_base(u16 N, StringView str);
|
[[nodiscard]] static ErrorOr<SignedBigInteger> from_base(u16 N, StringView str);
|
||||||
[[nodiscard]] ErrorOr<String> to_base(u16 N) const;
|
[[nodiscard]] ErrorOr<String> to_base(u16 N) const;
|
||||||
[[nodiscard]] ByteString to_base_deprecated(u16 N) const;
|
[[nodiscard]] ByteString to_base_deprecated(u16 N) const;
|
||||||
|
|
||||||
|
@ -171,5 +171,5 @@ struct AK::Formatter<Crypto::SignedBigInteger> : AK::Formatter<Crypto::UnsignedB
|
||||||
inline Crypto::SignedBigInteger
|
inline Crypto::SignedBigInteger
|
||||||
operator""_sbigint(char const* string, size_t length)
|
operator""_sbigint(char const* string, size_t length)
|
||||||
{
|
{
|
||||||
return Crypto::SignedBigInteger::from_base(10, { string, length });
|
return MUST(Crypto::SignedBigInteger::from_base(10, { string, length }));
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,16 +132,22 @@ size_t UnsignedBigInteger::export_data(Bytes data, bool remove_leading_zeros) co
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsignedBigInteger UnsignedBigInteger::from_base(u16 N, StringView str)
|
ErrorOr<UnsignedBigInteger> UnsignedBigInteger::from_base(u16 N, StringView str)
|
||||||
{
|
{
|
||||||
VERIFY(N <= 36);
|
VERIFY(N <= 36);
|
||||||
UnsignedBigInteger result;
|
UnsignedBigInteger result;
|
||||||
UnsignedBigInteger base { N };
|
UnsignedBigInteger base { N };
|
||||||
|
|
||||||
for (auto& c : str) {
|
for (auto const& c : str) {
|
||||||
if (c == '_')
|
if (c == '_')
|
||||||
continue;
|
continue;
|
||||||
result = result.multiplied_by(base).plus(parse_ascii_base36_digit(c));
|
if (!is_ascii_base36_digit(c))
|
||||||
|
return Error::from_string_literal("Invalid Base36 digit");
|
||||||
|
auto digit = parse_ascii_base36_digit(c);
|
||||||
|
if (digit >= N)
|
||||||
|
return Error::from_string_literal("Base36 digit out of range");
|
||||||
|
|
||||||
|
result = result.multiplied_by(base).plus(digit);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ public:
|
||||||
|
|
||||||
size_t export_data(Bytes, bool remove_leading_zeros = false) const;
|
size_t export_data(Bytes, bool remove_leading_zeros = false) const;
|
||||||
|
|
||||||
[[nodiscard]] static UnsignedBigInteger from_base(u16 N, StringView str);
|
[[nodiscard]] static ErrorOr<UnsignedBigInteger> from_base(u16 N, StringView str);
|
||||||
[[nodiscard]] ErrorOr<String> to_base(u16 N) const;
|
[[nodiscard]] ErrorOr<String> to_base(u16 N) const;
|
||||||
[[nodiscard]] ByteString to_base_deprecated(u16 N) const;
|
[[nodiscard]] ByteString to_base_deprecated(u16 N) const;
|
||||||
|
|
||||||
|
@ -161,5 +161,5 @@ struct AK::Formatter<Crypto::UnsignedBigInteger> : Formatter<StringView> {
|
||||||
inline Crypto::UnsignedBigInteger
|
inline Crypto::UnsignedBigInteger
|
||||||
operator""_bigint(char const* string, size_t length)
|
operator""_bigint(char const* string, size_t length)
|
||||||
{
|
{
|
||||||
return Crypto::UnsignedBigInteger::from_base(10, { string, length });
|
return MUST(Crypto::UnsignedBigInteger::from_base(10, { string, length }));
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,12 +273,12 @@ Bytecode::CodeGenerationErrorOr<void> BigIntLiteral::generate_bytecode(Bytecode:
|
||||||
auto integer = [&] {
|
auto integer = [&] {
|
||||||
if (m_value[0] == '0' && m_value.length() >= 3)
|
if (m_value[0] == '0' && m_value.length() >= 3)
|
||||||
if (m_value[1] == 'x' || m_value[1] == 'X')
|
if (m_value[1] == 'x' || m_value[1] == 'X')
|
||||||
return Crypto::SignedBigInteger::from_base(16, m_value.substring(2, m_value.length() - 3));
|
return MUST(Crypto::SignedBigInteger::from_base(16, m_value.substring(2, m_value.length() - 3)));
|
||||||
if (m_value[1] == 'o' || m_value[1] == 'O')
|
if (m_value[1] == 'o' || m_value[1] == 'O')
|
||||||
return Crypto::SignedBigInteger::from_base(8, m_value.substring(2, m_value.length() - 3));
|
return MUST(Crypto::SignedBigInteger::from_base(8, m_value.substring(2, m_value.length() - 3)));
|
||||||
if (m_value[1] == 'b' || m_value[1] == 'B')
|
if (m_value[1] == 'b' || m_value[1] == 'B')
|
||||||
return Crypto::SignedBigInteger::from_base(2, m_value.substring(2, m_value.length() - 3));
|
return MUST(Crypto::SignedBigInteger::from_base(2, m_value.substring(2, m_value.length() - 3)));
|
||||||
return Crypto::SignedBigInteger::from_base(10, m_value.substring(0, m_value.length() - 1));
|
return MUST(Crypto::SignedBigInteger::from_base(10, m_value.substring(0, m_value.length() - 1)));
|
||||||
}();
|
}();
|
||||||
|
|
||||||
generator.emit<Bytecode::Op::NewBigInt>(integer);
|
generator.emit<Bytecode::Op::NewBigInt>(integer);
|
||||||
|
|
|
@ -673,7 +673,7 @@ double string_to_number(StringView string)
|
||||||
|
|
||||||
// 4. Return StringNumericValue of literal.
|
// 4. Return StringNumericValue of literal.
|
||||||
if (result->base != 10) {
|
if (result->base != 10) {
|
||||||
auto bigint = Crypto::UnsignedBigInteger::from_base(result->base, result->literal);
|
auto bigint = MUST(Crypto::UnsignedBigInteger::from_base(result->base, result->literal));
|
||||||
return bigint.to_double();
|
return bigint.to_double();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,7 +842,7 @@ static Optional<BigInt*> string_to_bigint(VM& vm, StringView string)
|
||||||
|
|
||||||
// 4. Let mv be the MV of literal.
|
// 4. Let mv be the MV of literal.
|
||||||
// 5. Assert: mv is an integer.
|
// 5. Assert: mv is an integer.
|
||||||
auto bigint = Crypto::SignedBigInteger::from_base(result->base, result->literal);
|
auto bigint = MUST(Crypto::SignedBigInteger::from_base(result->base, result->literal));
|
||||||
if (result->is_negative && (bigint != BIGINT_ZERO))
|
if (result->is_negative && (bigint != BIGINT_ZERO))
|
||||||
bigint.negate();
|
bigint.negate();
|
||||||
|
|
||||||
|
|
|
@ -936,7 +936,8 @@ private:
|
||||||
auto string_view = TRY(Bindings::throw_dom_exception_if_needed(vm, [&string]() {
|
auto string_view = TRY(Bindings::throw_dom_exception_if_needed(vm, [&string]() {
|
||||||
return string->utf8_string_view();
|
return string->utf8_string_view();
|
||||||
}));
|
}));
|
||||||
return JS::BigInt::create(vm, ::Crypto::SignedBigInteger::from_base(10, string_view.substring_view(0, string_view.length() - 1)));
|
auto bigint = MUST(::Crypto::SignedBigInteger::from_base(10, string_view.substring_view(0, string_view.length() - 1)));
|
||||||
|
return JS::BigInt::create(vm, bigint);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue