Skip to content

Commit

Permalink
fix DataView.prototype.{ getFloat16, setFloat16 } conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
zloirock committed Sep 25, 2023
1 parent 4e6ebcd commit c0f549d
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 43 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -2,7 +2,7 @@
##### Unreleased
- Added [`ArrayBuffer.prototype.{ transfer, transferToFixedLength }`](https://github.com/tc39/proposal-arraybuffer-transfer) and support transferring of `ArrayBuffer`s via [`structuredClone`](https://html.spec.whatwg.org/multipage/structured-data.html#dom-structuredclone) to engines with `MessageChannel`
- Optimized [`Math.f16round`](https://github.com/tc39/proposal-float16array) polyfill
- Fixed [some conversion cases](https://github.com/petamoriken/float16/issues/1046) of `Math.f16round`
- Fixed [some conversion cases](https://github.com/petamoriken/float16/issues/1046) of [`Math.f16round` and `DataView.prototype.{ getFloat16, setFloat16 }`](https://github.com/tc39/proposal-float16array)
- Fully forced polyfilling of [the TC39 `Observable` proposal](https://github.com/tc39/proposal-observable) because of incompatibility with [the new WHATWG `Observable` proposal](https://github.com/WICG/observable)
- Added an extra workaround of errors with exotic environment objects in `Symbol` polyfill, [#1289](https://github.com/zloirock/core-js/issues/1289)
- Compat data improvements:
Expand Down
3 changes: 2 additions & 1 deletion packages/core-js/internals/array-buffer.js
Expand Up @@ -12,6 +12,7 @@ var anInstance = require('../internals/an-instance');
var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');
var toLength = require('../internals/to-length');
var toIndex = require('../internals/to-index');
var fround = require('../internals/math-fround');
var IEEE754 = require('../internals/ieee754');
var getPrototypeOf = require('../internals/object-get-prototype-of');
var setPrototypeOf = require('../internals/object-set-prototype-of');
Expand Down Expand Up @@ -62,7 +63,7 @@ var unpackInt32 = function (buffer) {
};

var packFloat32 = function (number) {
return packIEEE754(number, 23, 4);
return packIEEE754(fround(number), 23, 4);
};

var packFloat64 = function (number) {
Expand Down
29 changes: 9 additions & 20 deletions packages/core-js/internals/ieee754.js
@@ -1,30 +1,19 @@
'use strict';
// IEEE754 conversions based on https://github.com/feross/ieee754
var sign = require('../internals/math-sign');
var trunc = require('../internals/math-trunc');

var $Array = Array;
var abs = Math.abs;
var pow = Math.pow;
var floor = Math.floor;
var log = Math.log;
var LN2 = Math.LN2;

var roundToEven = function (number) {
var truncated = trunc(number);
var delta = abs(number - truncated);
if (delta > 0.5 || delta === 0.5 && truncated % 2 !== 0) {
return truncated + sign(number);
} return truncated;
};

var pack = function (number, mantissaLength, bytes) {
var buffer = $Array(bytes);
var exponentLength = bytes * 8 - mantissaLength - 1;
var eMax = (1 << exponentLength) - 1;
var eBias = eMax >> 1;
var rt = mantissaLength === 23 ? pow(2, -24) - pow(2, -77) : 0;
var s = number < 0 || number === 0 && 1 / number < 0 ? 1 : 0;
var sign = number < 0 || number === 0 && 1 / number < 0 ? 1 : 0;
var index = 0;
var exponent, mantissa, c;
number = abs(number);
Expand Down Expand Up @@ -53,10 +42,10 @@ var pack = function (number, mantissaLength, bytes) {
mantissa = 0;
exponent = eMax;
} else if (exponent + eBias >= 1) {
mantissa = roundToEven((number * c - 1) * pow(2, mantissaLength));
mantissa = (number * c - 1) * pow(2, mantissaLength);
exponent += eBias;
} else {
mantissa = roundToEven(number * pow(2, eBias - 1) * pow(2, mantissaLength));
mantissa = number * pow(2, eBias - 1) * pow(2, mantissaLength);
exponent = 0;
}
}
Expand All @@ -72,7 +61,7 @@ var pack = function (number, mantissaLength, bytes) {
exponent /= 256;
exponentLength -= 8;
}
buffer[--index] |= s * 128;
buffer[--index] |= sign * 128;
return buffer;
};

Expand All @@ -83,10 +72,10 @@ var unpack = function (buffer, mantissaLength) {
var eBias = eMax >> 1;
var nBits = exponentLength - 7;
var index = bytes - 1;
var s = buffer[index--];
var exponent = s & 127;
var sign = buffer[index--];
var exponent = sign & 127;
var mantissa;
s >>= 7;
sign >>= 7;
while (nBits > 0) {
exponent = exponent * 256 + buffer[index--];
nBits -= 8;
Expand All @@ -101,11 +90,11 @@ var unpack = function (buffer, mantissaLength) {
if (exponent === 0) {
exponent = 1 - eBias;
} else if (exponent === eMax) {
return mantissa ? NaN : s ? -Infinity : Infinity;
return mantissa ? NaN : sign ? -Infinity : Infinity;
} else {
mantissa += pow(2, mantissaLength);
exponent -= eBias;
} return (s ? -1 : 1) * mantissa * pow(2, exponent - mantissaLength);
} return (sign ? -1 : 1) * mantissa * pow(2, exponent - mantissaLength);
};

module.exports = {
Expand Down
3 changes: 2 additions & 1 deletion packages/core-js/modules/esnext.data-view.set-float16.js
Expand Up @@ -4,6 +4,7 @@ var uncurryThis = require('../internals/function-uncurry-this');
var classof = require('../internals/classof');
var toIndex = require('../internals/to-index');
var packIEEE754 = require('../internals/ieee754').pack;
var f16round = require('../internals/math-f16round');

var $TypeError = TypeError;
// eslint-disable-next-line es/no-typed-arrays -- safe
Expand All @@ -15,7 +16,7 @@ $({ target: 'DataView', proto: true }, {
setFloat16: function setFloat16(byteOffset, value /* , littleEndian */) {
if (classof(this) !== 'DataView') throw new $TypeError('Incorrect receiver');
var offset = toIndex(byteOffset);
var bytes = packIEEE754(+value, 10, 2);
var bytes = packIEEE754(f16round(value), 10, 2);
return setUint16(this, offset, bytes[1] << 8 | bytes[0], arguments.length > 2 ? arguments[2] : false);
}
});
22 changes: 22 additions & 0 deletions tests/unit-global/esnext.data-view.set-float16.js
Expand Up @@ -41,4 +41,26 @@ QUnit.test('DataView.prototype.{ getFloat16, setFloat16 }', assert => {
assert.same(view.getUint16(0, LE), bin, `DataView.prototype.setFloat16 + DataView.prototype.getUint16, LE: ${ LE }, ${ toString(f16) } -> ${ toString(bin) }`);
assert.same(view.getFloat16(0, LE), f16, `DataView.prototype.setFloat16 + DataView.prototype.getFloat16, LE: ${ LE }, ${ toString(f16) }`);
}

const MAX_FLOAT16 = 65504;
const MIN_FLOAT16 = 2 ** -24;

const conversions = [
[1.337, 1.3369140625],
[0.499994, 0.5],
[7.9999999, 8],
[MAX_FLOAT16, MAX_FLOAT16],
[-MAX_FLOAT16, -MAX_FLOAT16],
[MIN_FLOAT16, MIN_FLOAT16],
[-MIN_FLOAT16, -MIN_FLOAT16],
[MIN_FLOAT16 / 2, 0],
[-MIN_FLOAT16 / 2, -0],
[2.980232238769531911744490042422139897126953655970282852649688720703125e-8, MIN_FLOAT16],
[-2.980232238769531911744490042422139897126953655970282852649688720703125e-8, -MIN_FLOAT16],
];

for (const [from, to] of conversions) for (const LE of [false, true]) {
view.setFloat16(0, from, LE);
assert.same(view.getFloat16(0, LE), to, `DataView.prototype.setFloat16 + DataView.prototype.getFloat16, LE: ${ LE }, ${ toString(from) } -> ${ toString(to) }`);
}
});
20 changes: 10 additions & 10 deletions tests/unit-global/esnext.math.f16round.js
Expand Up @@ -23,17 +23,17 @@ QUnit.test('Math.f16round', assert => {
assert.same(f16round(MAX_VALUE), Infinity);
assert.same(f16round(-MAX_VALUE), -Infinity);

const maxFloat16 = 65504;
const minFloat16 = 2 ** -24;
const MAX_FLOAT16 = 65504;
const MIN_FLOAT16 = 2 ** -24;

assert.same(f16round(maxFloat16), maxFloat16);
assert.same(f16round(-maxFloat16), -maxFloat16);
assert.same(f16round(minFloat16), minFloat16);
assert.same(f16round(-minFloat16), -minFloat16);
assert.same(f16round(minFloat16 / 2), 0);
assert.same(f16round(-minFloat16 / 2), -0);
assert.same(f16round(2.980232238769531911744490042422139897126953655970282852649688720703125e-8), minFloat16);
assert.same(f16round(-2.980232238769531911744490042422139897126953655970282852649688720703125e-8), -minFloat16);
assert.same(f16round(MAX_FLOAT16), MAX_FLOAT16);
assert.same(f16round(-MAX_FLOAT16), -MAX_FLOAT16);
assert.same(f16round(MIN_FLOAT16), MIN_FLOAT16);
assert.same(f16round(-MIN_FLOAT16), -MIN_FLOAT16);
assert.same(f16round(MIN_FLOAT16 / 2), 0);
assert.same(f16round(-MIN_FLOAT16 / 2), -0);
assert.same(f16round(2.980232238769531911744490042422139897126953655970282852649688720703125e-8), MIN_FLOAT16);
assert.same(f16round(-2.980232238769531911744490042422139897126953655970282852649688720703125e-8), -MIN_FLOAT16);

assert.same(f16round(1.337), 1.3369140625);
assert.same(f16round(0.499994), 0.5);
Expand Down
20 changes: 10 additions & 10 deletions tests/unit-pure/esnext.math.f16round.js
Expand Up @@ -22,17 +22,17 @@ QUnit.test('Math.f16round', assert => {
assert.same(f16round(MAX_VALUE), Infinity);
assert.same(f16round(-MAX_VALUE), -Infinity);

const maxFloat16 = 65504;
const minFloat16 = 2 ** -24;
const MAX_FLOAT16 = 65504;
const MIN_FLOAT16 = 2 ** -24;

assert.same(f16round(maxFloat16), maxFloat16);
assert.same(f16round(-maxFloat16), -maxFloat16);
assert.same(f16round(minFloat16), minFloat16);
assert.same(f16round(-minFloat16), -minFloat16);
assert.same(f16round(minFloat16 / 2), 0);
assert.same(f16round(-minFloat16 / 2), -0);
assert.same(f16round(2.980232238769531911744490042422139897126953655970282852649688720703125e-8), minFloat16);
assert.same(f16round(-2.980232238769531911744490042422139897126953655970282852649688720703125e-8), -minFloat16);
assert.same(f16round(MAX_FLOAT16), MAX_FLOAT16);
assert.same(f16round(-MAX_FLOAT16), -MAX_FLOAT16);
assert.same(f16round(MIN_FLOAT16), MIN_FLOAT16);
assert.same(f16round(-MIN_FLOAT16), -MIN_FLOAT16);
assert.same(f16round(MIN_FLOAT16 / 2), 0);
assert.same(f16round(-MIN_FLOAT16 / 2), -0);
assert.same(f16round(2.980232238769531911744490042422139897126953655970282852649688720703125e-8), MIN_FLOAT16);
assert.same(f16round(-2.980232238769531911744490042422139897126953655970282852649688720703125e-8), -MIN_FLOAT16);

assert.same(f16round(1.337), 1.3369140625);
assert.same(f16round(0.499994), 0.5);
Expand Down

0 comments on commit c0f549d

Please sign in to comment.