From 8dd16259287f58f9273002717ec4d27e97127719 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:43:14 +0200 Subject: Merging upstream version 127.0. Signed-off-by: Daniel Baumann --- js/src/tests/non262/Math/f16round.js | 155 +++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 js/src/tests/non262/Math/f16round.js (limited to 'js/src/tests/non262/Math/f16round.js') 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"); -- cgit v1.2.3