@@ -243,6 +243,7 @@ function yyBuffer( _size, _type, _alignment, _srcbytebuff ) {
243
243
}
244
244
}
245
245
}
246
+
246
247
if ( ! DataView . prototype . getFloat16 ) {
247
248
// #################################################################################################
248
249
/// Function: getFloat16
@@ -331,33 +332,52 @@ if (!DataView.prototype.setFloat16) {
331
332
/// const dataView = new DataView(new ArrayBuffer(2));
332
333
/// dataView.setFloat16(0, 1.0, true); // Write float16 value 1.0 in little-endian
333
334
// #################################################################################################
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 ;
352
351
} 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
+ }
360
377
}
378
+
379
+ const float16 = sign | ( exponent << 10 ) | mantissa ;
380
+ this . setUint16 ( offset , float16 , littleEndian ) ;
361
381
} ;
362
382
}
363
383
0 commit comments