Skip to content

Commit f78dd9b

Browse files
Fixed bug on the setFloat16 used IEEE 754 standards reference
External: https://en.wikipedia.org/wiki/Half-precision_floating-point_format
1 parent a675126 commit f78dd9b

File tree

1 file changed

+45
-25
lines changed

1 file changed

+45
-25
lines changed

scripts/yyBuffer.js

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ function yyBuffer( _size, _type, _alignment, _srcbytebuff ) {
243243
}
244244
}
245245
}
246+
246247
if (!DataView.prototype.getFloat16) {
247248
// #################################################################################################
248249
/// Function: getFloat16
@@ -331,33 +332,52 @@ if (!DataView.prototype.setFloat16) {
331332
/// const dataView = new DataView(new ArrayBuffer(2));
332333
/// dataView.setFloat16(0, 1.0, true); // Write float16 value 1.0 in little-endian
333334
// #################################################################################################
334-
DataView.prototype.setFloat16 = function (offset, value, littleEndian = true) {
335-
// Define a custom setFloat16 method if it doesn't exist
336-
// offset: The offset where the 16-bit float will be written
337-
// value: The float16 value to write
338-
// littleEndian: Specifies the endianness of the data (true for little-endian, false for big-endian)
339-
340-
// Ensure the value is within the representable range of float16
341-
if (value < -65504.0 || value > 65504.0) {
342-
throw new RangeError("Float16 value is out of range.");
343-
}
344-
345-
// Handle special cases for zero and NaN
346-
if (value === 0) {
347-
// Zero
348-
this.setUint16(offset, 0, littleEndian);
349-
} else if (isNaN(value)) {
350-
// NaN
351-
this.setUint16(offset, 0x7E00, littleEndian); // NaN representation
335+
DataView.prototype.setFloat16 = function(offset, value, littleEndian = true) {
336+
let sign = 0;
337+
let exponent = 0;
338+
let mantissa = 0;
339+
340+
// Used references: https://en.wikipedia.org/wiki/Half-precision_floating-point_format
341+
if (isNaN(value)) {
342+
// If the value is NaN, use the standard NaN representation for float16.
343+
mantissa = 0x200;
344+
exponent = 0x1F;
345+
} else if (value === Infinity || value === -Infinity) {
346+
// Handling Infinity.
347+
exponent = 0x1F;
348+
} else if (value === 0) {
349+
// Handling zero (both positive and negative).
350+
sign = (1 / value === -Infinity) ? 0x8000 : 0;
352351
} else {
353-
// For non-zero, non-NaN values:
354-
const sign = value < 0 ? 0x8000 : 0; // Determine the sign bit
355-
const absValue = Math.abs(value);
356-
const exponent = Math.floor(Math.log2(absValue)) + 15; // Calculate the exponent
357-
const mantissa = Math.round(absValue * Math.pow(2, 10 - exponent)); // Calculate the mantissa
358-
const uint16Value = sign | (exponent << 10) | mantissa; // Combine sign, exponent, and mantissa
359-
this.setUint16(offset, uint16Value, littleEndian); // Write the uint16 representation
352+
sign = value < 0 ? 0x8000 : 0;
353+
value = Math.abs(value);
354+
355+
if (value >= Math.pow(2, -14)) {
356+
// Handle normal numbers.
357+
let exponentAndMantissa = Math.floor(Math.log2(value) + 15);
358+
exponent = exponentAndMantissa;
359+
mantissa = Math.floor((value / Math.pow(2, exponent - 15) - 1) * 1024);
360+
361+
if (mantissa === 1024) {
362+
// Handle rounding that causes exponent overflow.
363+
exponentAndMantissa += 1;
364+
exponent = exponentAndMantissa;
365+
mantissa = 0;
366+
}
367+
368+
if (exponentAndMantissa > 30) {
369+
// Handle overflow to Infinity.
370+
exponent = 0x1F;
371+
mantissa = 0;
372+
}
373+
} else {
374+
// Handle subnormal numbers.
375+
mantissa = Math.floor(value / Math.pow(2, -24));
376+
}
360377
}
378+
379+
const float16 = sign | (exponent << 10) | mantissa;
380+
this.setUint16(offset, float16, littleEndian);
361381
};
362382
}
363383

0 commit comments

Comments
 (0)