Skip to content

Commit a675126

Browse files
Adds support to Float16 values to be read, write and peek in a buffer.
1 parent c668b30 commit a675126

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

scripts/yyBuffer.js

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,124 @@ function yyBuffer( _size, _type, _alignment, _srcbytebuff ) {
243243
}
244244
}
245245
}
246+
if (!DataView.prototype.getFloat16) {
247+
// #################################################################################################
248+
/// Function: getFloat16
249+
/// Description:
250+
/// Retrieve and decode a 16-bit floating-point number from a DataView.
251+
///
252+
/// Parameters:
253+
/// byteOffset - The offset where the 16-bit float is stored.
254+
/// littleEndian - Specifies the endianness of the data (true for little-endian, false for big-endian).
255+
///
256+
/// Returns:
257+
/// The decoded 16-bit floating-point number.
258+
/// If the input data is invalid or out of range, NaN is returned.
259+
// #################################################################################################
260+
DataView.prototype.getFloat16 = function (byteOffset, littleEndian) {
261+
// Define a custom getFloat16 method if it doesn't exist
262+
// byteOffset: The offset where the 16-bit float is stored
263+
// littleEndian: Specifies the endianness of the data
264+
265+
// Read the 16-bit float as an unsigned integer
266+
const uint16 = this.getUint16(byteOffset, littleEndian);
267+
268+
// Extract the sign bit (bit 15)
269+
const sign = (uint16 & 0x8000) ? -1 : 1;
270+
271+
// Extract the exponent bits (bits 10-14)
272+
const exponent = (uint16 >> 10) & 0x1F;
273+
274+
// Extract the mantissa bits (bits 0-9)
275+
const mantissa = uint16 & 0x3FF;
276+
277+
if (exponent === 0) {
278+
// If exponent is 0, it's a denormalized number or zero
279+
if (mantissa === 0) {
280+
// Zero
281+
return sign * 0.0;
282+
} else {
283+
// Denormalized number
284+
// Calculate the value using the formula for denormalized numbers
285+
return sign * Math.pow(2, -14) * (mantissa / 1024);
286+
}
287+
} else if (exponent === 31) {
288+
// If exponent is 31, it's infinity or NaN
289+
if (mantissa === 0) {
290+
// Positive or negative infinity
291+
return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
292+
} else {
293+
// NaN
294+
return NaN;
295+
}
296+
} else {
297+
// Normalized number
298+
// Calculate the value using the formula for normalized numbers
299+
return sign * Math.pow(2, exponent - 15) * (1 + mantissa / 1024);
300+
}
301+
};
302+
}
303+
304+
if (!DataView.prototype.setFloat16) {
305+
// #################################################################################################
306+
/// Function: setFloat16
307+
/// Description:
308+
/// Encode and write a 16-bit floating-point number (float16) to a DataView.
309+
///
310+
/// Parameters:
311+
/// offset - The offset where the float16 will be written in the DataView.
312+
/// value - The float16 value to encode and write.
313+
/// littleEndian - Optional. Specifies the endianness of the data (true for little-endian, false for big-endian).
314+
///
315+
/// Returns:
316+
/// None.
317+
///
318+
/// Throws:
319+
/// - RangeError if the provided float16 value is out of the representable range for float16.
320+
///
321+
/// Details:
322+
/// The function encodes the provided float16 value as per IEEE 754-2008 standard for half-precision
323+
/// floating-point numbers and writes it to the specified offset in the DataView. If the value is
324+
/// outside the representable range for float16, a RangeError is thrown.
325+
///
326+
/// Special cases:
327+
/// - If the value is 0, it is written as a positive zero.
328+
/// - If the value is NaN, it is written as the NaN representation.
329+
///
330+
/// Example Usage:
331+
/// const dataView = new DataView(new ArrayBuffer(2));
332+
/// dataView.setFloat16(0, 1.0, true); // Write float16 value 1.0 in little-endian
333+
// #################################################################################################
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
352+
} 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
360+
}
361+
};
362+
}
363+
246364

247365
// #############################################################################################
248366
/// Function:<summary>
@@ -470,6 +588,11 @@ yyBuffer.prototype.yyb_read = function(_type) {
470588
res = new Long( this.m_DataView.getUint32(this.m_BufferIndex, true), 0);
471589
this.m_BufferIndex += 4;
472590
break;
591+
592+
case eBuffer_F16:
593+
res = this.m_DataView.getFloat16(this.m_BufferIndex, true);
594+
this.m_BufferIndex += 2;
595+
break;
473596
case eBuffer_F32:
474597
res = this.m_DataView.getFloat32(this.m_BufferIndex, true);
475598
this.m_BufferIndex += 4;
@@ -478,6 +601,7 @@ yyBuffer.prototype.yyb_read = function(_type) {
478601
res = this.m_DataView.getFloat64(this.m_BufferIndex, true);
479602
this.m_BufferIndex += 8;
480603
break;
604+
481605
case eBuffer_U64:
482606
var low = this.m_DataView.getUint32(this.m_BufferIndex, true);
483607
this.m_BufferIndex += 4;
@@ -1260,6 +1384,11 @@ yyBuffer.prototype.yyb_write = function(_type, _value) {
12601384
this.m_DataView.setUint32(this.m_BufferIndex, _value, true);
12611385
this.m_BufferIndex += 4;
12621386
break;
1387+
1388+
case eBuffer_F16:
1389+
this.m_DataView.setFloat16(this.m_BufferIndex, _value, true);
1390+
this.m_BufferIndex += 2;
1391+
break;
12631392
case eBuffer_F32:
12641393
this.m_DataView.setFloat32(this.m_BufferIndex, _value, true);
12651394
this.m_BufferIndex += 4;
@@ -1268,6 +1397,7 @@ yyBuffer.prototype.yyb_write = function(_type, _value) {
12681397
this.m_DataView.setFloat64(this.m_BufferIndex, _value, true);
12691398
this.m_BufferIndex += 8;
12701399
break;
1400+
12711401
case eBuffer_U64:
12721402
var int64Val = yyGetInt64(_value);
12731403
this.m_DataView.setUint32(this.m_BufferIndex, int64Val.low, true);
@@ -1336,12 +1466,17 @@ yyBuffer.prototype.yyb_peek = function(_type, _offset) {
13361466
case eBuffer_U32:
13371467
res = this.m_DataView.getUint32(_offset, true);
13381468
break;
1469+
1470+
case eBuffer_F16:
1471+
res = this.m_DataView.getFloat16(_offset, true);
1472+
break;
13391473
case eBuffer_F32:
13401474
res = this.m_DataView.getFloat32(_offset, true);
13411475
break;
13421476
case eBuffer_F64:
13431477
res = this.m_DataView.getFloat64(_offset, true);
13441478
break;
1479+
13451480
case eBuffer_U64:
13461481
var low = this.m_DataView.getUint32(_offset, true);
13471482
var high = this.m_DataView.getUint32(_offset + 4, true);

0 commit comments

Comments
 (0)