diff --git a/package-lock.json b/package-lock.json index cc1ddb0d78..e2bceb3ad0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@types/node": "^18.19.75", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", + "as-float": "^1.0.1", "diff": "^7.0.0", "esbuild": "^0.25.0", "eslint": "^8.57.1", @@ -953,6 +954,13 @@ "node": ">=8" } }, + "node_modules/as-float": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/as-float/-/as-float-1.0.1.tgz", + "integrity": "sha512-TsN1UpoFdtzuKXqqpdnGbFuMYnK/eqMEjd2xVvACG29H/v4KLx+UD+tHRz9v6zO+Ge/AR/uskSruBIPZrchhHw==", + "dev": true, + "license": "MIT" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3054,6 +3062,12 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "as-float": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/as-float/-/as-float-1.0.1.tgz", + "integrity": "sha512-TsN1UpoFdtzuKXqqpdnGbFuMYnK/eqMEjd2xVvACG29H/v4KLx+UD+tHRz9v6zO+Ge/AR/uskSruBIPZrchhHw==", + "dev": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", diff --git a/package.json b/package.json index 2b10b739a3..cf320be2a8 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@types/node": "^18.19.75", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", + "as-float": "^1.0.1", "diff": "^7.0.0", "esbuild": "^0.25.0", "eslint": "^8.57.1", diff --git a/src/glue/js/float.d.ts b/src/glue/js/float.d.ts index 8694f03b52..b116ad846c 100644 --- a/src/glue/js/float.d.ts +++ b/src/glue/js/float.d.ts @@ -7,3 +7,4 @@ declare function f32_as_i32(value: f32): i32; declare function i32_as_f32(value: i32): f32; declare function f64_as_i64(value: f64): i64; declare function i64_as_f64(value: i64): f64; +declare function f64_pow(value: f64, exponent: f64): f64; diff --git a/src/glue/js/float.js b/src/glue/js/float.js index 090af6cf96..6b68fdfef1 100644 --- a/src/glue/js/float.js +++ b/src/glue/js/float.js @@ -3,6 +3,8 @@ * @license Apache-2.0 */ +import { f64_pow } from "as-float"; + /* eslint-disable no-undef */ const F64 = new Float64Array(1); @@ -29,3 +31,5 @@ globalThis.i64_as_f64 = function i64_as_f64(value) { I32[1] = i64_high(value); return F64[0]; }; + +globalThis.f64_pow = f64_pow; diff --git a/src/util/math.ts b/src/util/math.ts index 25759f35d1..56655e921c 100644 --- a/src/util/math.ts +++ b/src/util/math.ts @@ -11,16 +11,10 @@ export function isPowerOf2(x: i32): bool { export function accuratePow64(x: f64, y: f64): f64 { if (!ASC_TARGET) { // ASC_TARGET == JS // Engines like V8, WebKit and SpiderMonkey uses powi fast path if exponent is integer - // This speculative optimization leads to loose precisions like 10 ** 208 != 1e208 - // or/and 10 ** -5 != 1e-5 anymore. For avoid this behaviour we are forcing exponent - // to fractional form and compensate this afterwards. - if (isFinite(y) && Math.abs(y) >= 2 && Math.trunc(y) == y) { - if (y < 0) { - return Math.pow(x, y + 0.5) / Math.pow(x, 0.5); - } else { - return Math.pow(x, y - 0.5) * Math.pow(x, 0.5); - } - } + // This speculative optimization leads to loose precisions like 10 ** -5 != 1e-5 anymore + // and introduces inconsistencies between different engines and versions + // For avoid this behavior we using bootstrap f64_pow function. + return f64_pow(x, y); } return Math.pow(x, y); }