summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/Math/f16round.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/non262/Math/f16round.js')
-rw-r--r--js/src/tests/non262/Math/f16round.js155
1 files changed, 155 insertions, 0 deletions
diff --git a/js/src/tests/non262/Math/f16round.js b/js/src/tests/non262/Math/f16round.js
new file mode 100644
index 0000000000..cf27346d37
--- /dev/null
+++ b/js/src/tests/non262/Math/f16round.js
@@ -0,0 +1,155 @@
+// |reftest| shell-option(--enable-float16array) skip-if(!Math.f16round)
+
+// Some tests regarding conversion to Float16
+assertEq(Math.f16round(), NaN);
+
+// Special values
+assertEq(Math.f16round(NaN), NaN);
+assertEq(Math.f16round(-Infinity), -Infinity);
+assertEq(Math.f16round(Infinity), Infinity);
+assertEq(Math.f16round(-0), -0);
+assertEq(Math.f16round(+0), +0);
+
+// Polyfill function for Float16 conversion, adapted from
+// https://github.com/petamoriken/float16/.
+// The original license is preseved below.
+function toFloat16(num) {
+ // MIT License
+
+ // Copyright (c) 2017-2024 Kenta Moriuchi
+
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
+ // of this software and associated documentation files (the "Software"), to deal
+ // in the Software without restriction, including without limitation the rights
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ // copies of the Software, and to permit persons to whom the Software is
+ // furnished to do so, subject to the following conditions:
+
+ // The above copyright notice and this permission notice shall be included in all
+ // copies or substantial portions of the Software.
+
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ // SOFTWARE.
+
+ const INVERSE_OF_EPSILON = 1 / Number.EPSILON;
+
+ /**
+ * rounds to the nearest value;
+ * if the number falls midway, it is rounded to the nearest value with an even least significant digit
+ * @param {number} num
+ * @returns {number}
+ */
+ function roundTiesToEven(num) {
+ return (num + INVERSE_OF_EPSILON) - INVERSE_OF_EPSILON;
+ }
+
+ const FLOAT16_MIN_VALUE = 6.103515625e-05;
+ const FLOAT16_MAX_VALUE = 65504;
+ const FLOAT16_EPSILON = 0.0009765625;
+
+ const FLOAT16_EPSILON_MULTIPLIED_BY_FLOAT16_MIN_VALUE = FLOAT16_EPSILON * FLOAT16_MIN_VALUE;
+ const FLOAT16_EPSILON_DEVIDED_BY_EPSILON = FLOAT16_EPSILON * INVERSE_OF_EPSILON;
+
+ function roundToFloat16(num) {
+ const number = +num;
+
+ // NaN, Infinity, -Infinity, 0, -0
+ if (!isFinite(number) || number === 0) {
+ return number;
+ }
+
+ // finite except 0, -0
+ const sign = number > 0 ? 1 : -1;
+ const absolute = Math.abs(number);
+
+ // small number
+ if (absolute < FLOAT16_MIN_VALUE) {
+ return sign * roundTiesToEven(absolute / FLOAT16_EPSILON_MULTIPLIED_BY_FLOAT16_MIN_VALUE) * FLOAT16_EPSILON_MULTIPLIED_BY_FLOAT16_MIN_VALUE;
+ }
+
+ const temp = (1 + FLOAT16_EPSILON_DEVIDED_BY_EPSILON) * absolute;
+ const result = temp - (temp - absolute);
+
+ // large number
+ if (result > FLOAT16_MAX_VALUE || isNaN(result)) {
+ return sign * Infinity;
+ }
+
+ return sign * result;
+ }
+
+ return roundToFloat16(num);
+};
+
+// A test on a certain range of numbers, including big numbers, so that
+// we get a loss in precision for some of them.
+for (var i = 0; i < 64; ++i) {
+ var p = Math.pow(2, i) + 1;
+ assertEq(Math.f16round(p), toFloat16(p));
+ assertEq(Math.f16round(-p), toFloat16(-p));
+}
+
+/********************************************
+/* Tests on maximal Float16 / Double values *
+/*******************************************/
+function maxValue(exponentWidth, significandWidth) {
+ var n = 0;
+ var maxExp = Math.pow(2, exponentWidth - 1) - 1;
+ for (var i = significandWidth; i >= 0; i--)
+ n += Math.pow(2, maxExp - i);
+ return n;
+}
+
+var DBL_MAX = maxValue(11, 52);
+assertEq(DBL_MAX, Number.MAX_VALUE); // sanity check
+
+// Finite as a double, too big for a float16
+assertEq(Math.f16round(DBL_MAX), Infinity);
+
+var FLT16_MAX = maxValue(5, 10);
+assertEq(Math.f16round(FLT16_MAX), FLT16_MAX);
+assertEq(Math.f16round(65519), FLT16_MAX); // round-nearest rounds down to FLT16_MAX
+assertEq(Math.f16round(65520), Infinity); // no longer rounds down to FLT16_MAX
+
+/*********************************************************
+/******* Tests on denormalizations and roundings *********
+/********************************************************/
+function minValue(exponentWidth, significandWidth) {
+ return Math.pow(2, -(Math.pow(2, exponentWidth - 1) - 2) - significandWidth);
+}
+
+var DBL_MIN = Math.pow(2, -1074);
+assertEq(DBL_MIN, Number.MIN_VALUE); // sanity check
+
+// Too small for a float16
+assertEq(Math.f16round(DBL_MIN), 0);
+
+var FLT16_MIN = minValue(5, 10);
+assertEq(Math.f16round(FLT16_MIN), FLT16_MIN);
+
+assertEq(Math.f16round(FLT16_MIN / 2), 0); // halfway, round-nearest rounds down to 0 (even)
+
+// FLT16_MIN + a small amount rounds up to FLT16_MIN
+// Constant taken from https://github.com/petamoriken/float16/
+assertEq(Math.f16round(2.980232238769531911744490042422139897126953655970282852649688720703125e-8), FLT16_MIN);
+
+assertEq(Math.f16round(-FLT16_MIN), -FLT16_MIN);
+assertEq(Math.f16round(-FLT16_MIN / 2), -0); // halfway, round-nearest rounds up to -0 (even)
+// -FLT16_MIN - a small amount rounds down to -FLT16_MIN
+// Constant taken from https://github.com/petamoriken/float16/
+assertEq(Math.f16round(2.980232238769531911744490042422139897126953655970282852649688720703125e-8), FLT16_MIN);
+
+// Test some constants from https://github.com/petamoriken/float16/
+assertEq(Math.f16round(0.499994), 0.5);
+assertEq(Math.f16round(1.337), 1.3369140625);
+
+// This will round incorrectly if the implementation first rounds to Float32,
+// then to Float16
+assertEq(Math.f16round(1.00048828125000022204), 1.0009765625);
+
+reportCompare(0, 0, "ok");