Jelajahi Sumber

AK+LibC+LibCrypto: Move FloatExtractor to AK/FloatingPoint.h

Dan Klishch 2 tahun lalu
induk
melakukan
17c9a3e8d9

+ 52 - 0
AK/FloatingPoint.h

@@ -12,6 +12,57 @@
 
 namespace AK {
 
+template<typename T>
+union FloatExtractor;
+
+#if ARCH(I386) || ARCH(X86_64) || ARCH(AARCH64)
+// This assumes long double is 80 bits, which is true with GCC on Intel platforms
+template<>
+union FloatExtractor<long double> {
+    static constexpr int mantissa_bits = 64;
+    static constexpr unsigned long long mantissa_max = ~0u;
+    static constexpr int exponent_bias = 16383;
+    static constexpr int exponent_bits = 15;
+    static constexpr unsigned exponent_max = 32767;
+    struct {
+        unsigned long long mantissa;
+        unsigned exponent : 15;
+        unsigned sign : 1;
+    };
+    long double d;
+};
+#endif
+
+template<>
+union FloatExtractor<double> {
+    static constexpr int mantissa_bits = 52;
+    static constexpr unsigned long long mantissa_max = (1ull << 52) - 1;
+    static constexpr int exponent_bias = 1023;
+    static constexpr int exponent_bits = 11;
+    static constexpr unsigned exponent_max = 2047;
+    struct {
+        unsigned long long mantissa : 52;
+        unsigned exponent : 11;
+        unsigned sign : 1;
+    };
+    double d;
+};
+
+template<>
+union FloatExtractor<float> {
+    static constexpr int mantissa_bits = 23;
+    static constexpr unsigned mantissa_max = (1 << 23) - 1;
+    static constexpr int exponent_bias = 127;
+    static constexpr int exponent_bits = 8;
+    static constexpr unsigned exponent_max = 255;
+    struct {
+        unsigned long long mantissa : 23;
+        unsigned exponent : 8;
+        unsigned sign : 1;
+    };
+    float d;
+};
+
 template<size_t S, size_t E, size_t M>
 requires(S <= 1 && E >= 1 && M >= 1 && (S + E + M) <= 64) class FloatingPointBits final {
 public:
@@ -183,6 +234,7 @@ constexpr float convert_to_native_float(I input) { return float_to_float<SingleF
 }
 
 using AK::DoubleFloatingPointBits;
+using AK::FloatExtractor;
 using AK::FloatingPointBits;
 using AK::SingleFloatingPointBits;
 

+ 1 - 51
Userland/Libraries/LibC/math.cpp

@@ -9,6 +9,7 @@
 
 #include <AK/BuiltinWrappers.h>
 #include <AK/ExtraMathConstants.h>
+#include <AK/FloatingPoint.h>
 #ifndef AK_ARCH_AARCH64
 #    include <AK/FPControl.h>
 #endif
@@ -61,57 +62,6 @@ enum class RoundingMode {
     ToEven = FE_TONEAREST
 };
 
-template<typename T>
-union FloatExtractor;
-
-#if ARCH(I386) || ARCH(X86_64) || ARCH(AARCH64)
-// This assumes long double is 80 bits, which is true with GCC on Intel platforms
-template<>
-union FloatExtractor<long double> {
-    static constexpr int mantissa_bits = 64;
-    static constexpr unsigned long long mantissa_max = ~0u;
-    static constexpr int exponent_bias = 16383;
-    static constexpr int exponent_bits = 15;
-    static constexpr unsigned exponent_max = 32767;
-    struct {
-        unsigned long long mantissa;
-        unsigned exponent : 15;
-        unsigned sign : 1;
-    };
-    long double d;
-};
-#endif
-
-template<>
-union FloatExtractor<double> {
-    static constexpr int mantissa_bits = 52;
-    static constexpr unsigned long long mantissa_max = (1ull << 52) - 1;
-    static constexpr int exponent_bias = 1023;
-    static constexpr int exponent_bits = 11;
-    static constexpr unsigned exponent_max = 2047;
-    struct {
-        unsigned long long mantissa : 52;
-        unsigned exponent : 11;
-        unsigned sign : 1;
-    };
-    double d;
-};
-
-template<>
-union FloatExtractor<float> {
-    static constexpr int mantissa_bits = 23;
-    static constexpr unsigned mantissa_max = (1 << 23) - 1;
-    static constexpr int exponent_bias = 127;
-    static constexpr int exponent_bits = 8;
-    static constexpr unsigned exponent_max = 255;
-    struct {
-        unsigned long long mantissa : 23;
-        unsigned exponent : 8;
-        unsigned sign : 1;
-    };
-    float d;
-};
-
 // This is much branchier than it really needs to be
 template<typename FloatType>
 static FloatType internal_to_integer(FloatType x, RoundingMode rounding_mode)

+ 27 - 48
Userland/Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp

@@ -8,6 +8,7 @@
 #include "UnsignedBigInteger.h"
 #include <AK/BuiltinWrappers.h>
 #include <AK/CharacterTypes.h>
+#include <AK/FloatingPoint.h>
 #include <AK/StringBuilder.h>
 #include <AK/StringHash.h>
 #include <LibCrypto/BigInt/Algorithms/UnsignedBigIntegerAlgorithms.h>
@@ -34,19 +35,6 @@ UnsignedBigInteger::UnsignedBigInteger(u8 const* ptr, size_t length)
     }
 }
 
-static constexpr u64 mantissa_size = 52;
-static constexpr u64 exponent_size = 11;
-static constexpr auto exponent_bias = (1 << (exponent_size - 1)) - 1;
-
-union DoubleExtractor {
-    struct {
-        unsigned long long mantissa : mantissa_size;
-        unsigned exponent : exponent_size;
-        unsigned sign : 1;
-    };
-    double double_value = 0;
-};
-
 UnsignedBigInteger::UnsignedBigInteger(double value)
 {
     // Because this is currently only used for LibJS we VERIFY some preconditions
@@ -61,11 +49,11 @@ UnsignedBigInteger::UnsignedBigInteger(double value)
         return;
     }
 
-    DoubleExtractor extractor;
-    extractor.double_value = value;
+    FloatExtractor<double> extractor;
+    extractor.d = value;
     VERIFY(!extractor.sign);
 
-    i32 real_exponent = extractor.exponent - exponent_bias;
+    i32 real_exponent = extractor.exponent - extractor.exponent_bias;
     VERIFY(real_exponent > 0);
 
     // Ensure we have enough space, we will need 2^exponent bits, so round up in words
@@ -73,10 +61,10 @@ UnsignedBigInteger::UnsignedBigInteger(double value)
     m_words.resize_and_keep_capacity(word_index);
 
     // Now we just need to put the mantissa with explicit 1 bit at the top at the proper location
-    u64 raw_mantissa = extractor.mantissa | (1ull << mantissa_size);
+    u64 raw_mantissa = extractor.mantissa | (1ull << extractor.mantissa_bits);
     VERIFY((raw_mantissa & 0xfff0000000000000) == 0x0010000000000000);
     // Shift it so the bits we need are at the top
-    raw_mantissa <<= 64 - mantissa_size - 1;
+    raw_mantissa <<= 64 - extractor.mantissa_bits - 1;
 
     // The initial bit needs to be exactly aligned with exponent, this is 1-indexed
     auto top_word_bit_offset = real_exponent % BITS_IN_WORD + 1;
@@ -88,7 +76,7 @@ UnsignedBigInteger::UnsignedBigInteger(double value)
     --word_index;
     // Shift used bits away
     raw_mantissa <<= top_word_bit_offset;
-    i32 bits_in_mantissa = mantissa_size + 1 - top_word_bit_offset;
+    i32 bits_in_mantissa = extractor.mantissa_bits + 1 - top_word_bit_offset;
     // Now just put everything at the top of the next words
 
     constexpr auto to_word_shift = 64 - BITS_IN_WORD;
@@ -198,12 +186,14 @@ double UnsignedBigInteger::to_double(UnsignedBigInteger::RoundingMode rounding_m
         return 0;
     --highest_bit;
 
+    using Extractor = FloatExtractor<double>;
+
     // Simple case if less than 2^53 since those number are all exactly representable in doubles
-    if (highest_bit < mantissa_size + 1)
+    if (highest_bit < Extractor::mantissa_bits + 1)
         return static_cast<double>(to_u64());
 
     // If it uses too many bit to represent in a double return infinity
-    if (highest_bit > exponent_bias)
+    if (highest_bit > Extractor::exponent_bias)
         return __builtin_huge_val();
 
     // Otherwise we have to take the top 53 bits, use those as the mantissa,
@@ -211,11 +201,11 @@ double UnsignedBigInteger::to_double(UnsignedBigInteger::RoundingMode rounding_m
     // so we have to ignore the very top bit.
 
     // Since we extract at most 53 bits it will take at most 3 words
-    static_assert(BITS_IN_WORD * 3 >= (mantissa_size + 1));
+    static_assert(BITS_IN_WORD * 3 >= (Extractor::mantissa_bits + 1));
     constexpr auto bits_in_u64 = 64;
-    static_assert(bits_in_u64 > mantissa_size + 1);
+    static_assert(bits_in_u64 > Extractor::mantissa_bits + 1);
 
-    auto bits_to_read = min(mantissa_size, highest_bit);
+    auto bits_to_read = min(static_cast<size_t>(Extractor::mantissa_bits), highest_bit);
 
     auto last_word_index = trimmed_length();
     VERIFY(last_word_index > 0);
@@ -267,7 +257,7 @@ double UnsignedBigInteger::to_double(UnsignedBigInteger::RoundingMode rounding_m
     }
 
     // Now the mantissa should be complete so shift it down
-    mantissa >>= bits_in_u64 - mantissa_size;
+    mantissa >>= bits_in_u64 - Extractor::mantissa_bits;
 
     if (rounding_mode == RoundingMode::IEEERoundAndTiesToEvenMantissa) {
         bool round_up = false;
@@ -327,13 +317,13 @@ double UnsignedBigInteger::to_double(UnsignedBigInteger::RoundingMode rounding_m
 
         if (round_up) {
             ++mantissa;
-            if ((mantissa & (1ull << mantissa_size)) != 0) {
+            if ((mantissa & (1ull << Extractor::mantissa_bits)) != 0) {
                 // we overflowed the mantissa
                 mantissa = 0;
                 highest_bit++;
 
                 // In which case it is possible we have to round to infinity
-                if (highest_bit > exponent_bias)
+                if (highest_bit > Extractor::exponent_bias)
                     return __builtin_huge_val();
             }
         }
@@ -341,14 +331,13 @@ double UnsignedBigInteger::to_double(UnsignedBigInteger::RoundingMode rounding_m
         VERIFY(rounding_mode == RoundingMode::RoundTowardZero);
     }
 
-    DoubleExtractor extractor;
-
-    extractor.exponent = highest_bit + exponent_bias;
+    Extractor extractor;
+    extractor.exponent = highest_bit + extractor.exponent_bias;
 
     VERIFY((mantissa & 0xfff0000000000000) == 0);
     extractor.mantissa = mantissa;
 
-    return extractor.double_value;
+    return extractor.d;
 }
 
 void UnsignedBigInteger::set_to_0()
@@ -627,25 +616,15 @@ UnsignedBigInteger::CompareResult UnsignedBigInteger::compare_to_double(double v
     if (is_zero())
         return CompareResult::DoubleGreaterThanBigInt;
 
-    constexpr u64 mantissa_size = 52;
-    constexpr u64 exponent_size = 11;
-    constexpr auto exponent_bias = (1 << (exponent_size - 1)) - 1;
-    union FloatExtractor {
-        struct {
-            unsigned long long mantissa : mantissa_size;
-            unsigned exponent : exponent_size;
-            unsigned sign : 1;
-        };
-        double d;
-    } extractor;
-
+    FloatExtractor<double> extractor;
     extractor.d = value;
+
     // Value cannot be negative at this point.
     VERIFY(extractor.sign == 0);
     // Exponent cannot be all set, as then we must be NaN or infinity.
-    VERIFY(extractor.exponent != (1 << exponent_size) - 1);
+    VERIFY(extractor.exponent != (1 << extractor.exponent_bits) - 1);
 
-    i32 real_exponent = extractor.exponent - exponent_bias;
+    i32 real_exponent = extractor.exponent - extractor.exponent_bias;
     if (real_exponent < 0) {
         // value is less than 1, and we cannot be zero so value must be less.
         return CompareResult::DoubleLessThanBigInt;
@@ -670,7 +649,7 @@ UnsignedBigInteger::CompareResult UnsignedBigInteger::compare_to_double(double v
     u64 mantissa_bits = extractor.mantissa;
 
     // We add the bit which represents the 1. of the double value calculation.
-    constexpr u64 mantissa_extended_bit = 1ull << mantissa_size;
+    constexpr u64 mantissa_extended_bit = 1ull << extractor.mantissa_bits;
 
     mantissa_bits |= mantissa_extended_bit;
 
@@ -684,9 +663,9 @@ UnsignedBigInteger::CompareResult UnsignedBigInteger::compare_to_double(double v
     VERIFY(msb_in_top_word_index == (BITS_IN_WORD - count_leading_zeroes(words()[next_bigint_word - 1]) - 1));
 
     // We will keep the bits which are still valid in the mantissa at the top of mantissa bits.
-    mantissa_bits <<= 64 - (mantissa_size + 1);
+    mantissa_bits <<= 64 - (extractor.mantissa_bits + 1);
 
-    auto bits_left_in_mantissa = mantissa_size + 1;
+    auto bits_left_in_mantissa = static_cast<size_t>(extractor.mantissa_bits) + 1;
 
     auto get_next_value_bits = [&](size_t num_bits) -> Word {
         VERIFY(num_bits < 63);