mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-20 19:45:12 +00:00
AK+LibC+LibCrypto: Move FloatExtractor to AK/FloatingPoint.h
This commit is contained in:
parent
2d75229192
commit
17c9a3e8d9
Notes:
sideshowbarker
2024-07-17 05:21:12 +09:00
Author: https://github.com/DanShaders 🔰 Commit: https://github.com/SerenityOS/serenity/commit/17c9a3e8d9 Pull-request: https://github.com/SerenityOS/serenity/pull/15796 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/BertalanD Reviewed-by: https://github.com/Hendiadyoin1 Reviewed-by: https://github.com/davidot ✅ Reviewed-by: https://github.com/linusg
3 changed files with 80 additions and 99 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue