From 0cd85ab0fc62b4b1e465f1375716a3481ecead68 Mon Sep 17 00:00:00 2001 From: Daniel Bertalan Date: Sun, 2 Jul 2023 18:28:26 +0200 Subject: [PATCH] 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::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. --- AK/NumericLimits.h | 9 ++++++--- Userland/Libraries/LibJS/Runtime/NumberConstructor.cpp | 2 +- .../LibJS/Tests/builtins/Number/Number-constants.js | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/AK/NumericLimits.h b/AK/NumericLimits.h index b71c2cb52c7..30db889cf3a 100644 --- a/AK/NumericLimits.h +++ b/AK/NumericLimits.h @@ -114,7 +114,8 @@ struct NumericLimits { template<> struct NumericLimits { 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 { template<> struct NumericLimits { 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 { template<> struct NumericLimits { 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; } diff --git a/Userland/Libraries/LibJS/Runtime/NumberConstructor.cpp b/Userland/Libraries/LibJS/Runtime/NumberConstructor.cpp index 6f11164b899..de2ce50bd21 100644 --- a/Userland/Libraries/LibJS/Runtime/NumberConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/NumberConstructor.cpp @@ -46,7 +46,7 @@ ThrowCompletionOr 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::max()), 0); - define_direct_property(vm.names.MIN_VALUE, Value(NumericLimits::min()), 0); + define_direct_property(vm.names.MIN_VALUE, Value(NumericLimits::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); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Number/Number-constants.js b/Userland/Libraries/LibJS/Tests/builtins/Number/Number-constants.js index 2958821546f..d1cb432dff3 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Number/Number-constants.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Number/Number-constants.js @@ -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); });