AK+LibJS: Make Number.MIN_VALUE a denormal

ECMA-262 implies that `MIN_VALUE` should be a denormalized value if
denormal arithmetic is supported. This is the case on x86-64 and AArch64
using standard GCC/Clang compilation settings.

test262 checks whether `Number.MIN_VALUE / 2.0` is equal to 0, which
only holds if `MIN_VALUE` is the smallest denormalized value.

This commit renames the existing `NumericLimits<FloatingPoint>::min()`
to `min_normal()` and adds a `min_denormal()` method to force users to
explicitly think about which one is appropriate for their use case. We
shouldn't follow the STL's confusingly designed interface in this
regard.
This commit is contained in:
Daniel Bertalan 2023-07-02 18:28:26 +02:00 committed by Linus Groh
parent 978fe3c6d5
commit 0cd85ab0fc
Notes: sideshowbarker 2024-07-17 10:05:47 +09:00
3 changed files with 9 additions and 4 deletions

View file

@ -114,7 +114,8 @@ struct NumericLimits<unsigned long long> {
template<>
struct NumericLimits<float> {
static constexpr float lowest() { return -__FLT_MAX__; }
static constexpr float min() { return __FLT_MIN__; }
static constexpr float min_normal() { return __FLT_MIN__; }
static constexpr float min_denormal() { return __FLT_DENORM_MIN__; }
static constexpr float max() { return __FLT_MAX__; }
static constexpr float epsilon() { return __FLT_EPSILON__; }
static constexpr bool is_signed() { return true; }
@ -124,7 +125,8 @@ struct NumericLimits<float> {
template<>
struct NumericLimits<double> {
static constexpr double lowest() { return -__DBL_MAX__; }
static constexpr double min() { return __DBL_MIN__; }
static constexpr double min_normal() { return __DBL_MIN__; }
static constexpr double min_denormal() { return __DBL_DENORM_MIN__; }
static constexpr double max() { return __DBL_MAX__; }
static constexpr double epsilon() { return __DBL_EPSILON__; }
static constexpr bool is_signed() { return true; }
@ -134,7 +136,8 @@ struct NumericLimits<double> {
template<>
struct NumericLimits<long double> {
static constexpr long double lowest() { return -__LDBL_MAX__; }
static constexpr long double min() { return __LDBL_MIN__; }
static constexpr long double min_normal() { return __LDBL_MIN__; }
static constexpr long double min_denormal() { return __LDBL_DENORM_MIN__; }
static constexpr long double max() { return __LDBL_MAX__; }
static constexpr long double epsilon() { return __LDBL_EPSILON__; }
static constexpr bool is_signed() { return true; }

View file

@ -46,7 +46,7 @@ ThrowCompletionOr<void> NumberConstructor::initialize(Realm& realm)
define_direct_property(vm.names.parseFloat, realm.intrinsics().parse_float_function(), attr);
define_direct_property(vm.names.EPSILON, Value(EPSILON_VALUE), 0);
define_direct_property(vm.names.MAX_VALUE, Value(NumericLimits<double>::max()), 0);
define_direct_property(vm.names.MIN_VALUE, Value(NumericLimits<double>::min()), 0);
define_direct_property(vm.names.MIN_VALUE, Value(NumericLimits<double>::min_denormal()), 0);
define_direct_property(vm.names.MAX_SAFE_INTEGER, Value(MAX_SAFE_INTEGER_VALUE), 0);
define_direct_property(vm.names.MIN_SAFE_INTEGER, Value(MIN_SAFE_INTEGER_VALUE), 0);
define_direct_property(vm.names.NEGATIVE_INFINITY, js_negative_infinity(), 0);

View file

@ -8,4 +8,6 @@ test("basic functionality", () => {
expect(Number.POSITIVE_INFINITY).toBe(Infinity);
expect(Number.NEGATIVE_INFINITY).toBe(-Infinity);
expect(Number.NaN).toBeNaN();
expect(Number.MIN_VALUE).toBeGreaterThan(0);
expect(Number.MIN_VALUE / 2.0).toBe(0);
});