Reputation: 1983
For (lossy) compression purposes, I'd like to be able to convert Javascript numbers into 16-bit float representation to be stored in Uint16Arrays (or Uint8Arrays, whichever's easiest.) Then I'd like to be able to convert back from the 2 bytes to a number. I don't need to perform any arithmetic on the 16-bit numbers, it's just for compact storage.
I'm having trouble finding an algorithm to do this. It doesn't need to be a IEEE standard, just something accurate to a few decimal places.
Floats are preferable to fixed point because I'd rather not have to pre-determine the range of values.
Upvotes: 3
Views: 2720
Reputation: 33618
The first step is to extract the exponent and normalized fraction of the number. In C, this is done using the frexp
function which isn't available in JavaScript. Googling for frexp javascript
yields a couple of implementations.
For example, here's a straight-forward implementation that extracts the bits directly from the IEEE representation using typed arrays. Here's a quick-and-dirty, inexact version using only Math
functions. Here's an exact (?) version.
The second step is to create your 16-bit FP number from the obtained exponent and mantissa using bit operations. Make sure to check the exponent range and to round the lower-precision mantissa for better accuracy.
Extract exponent and mantissa from your 16-bit FP number. Convert them to a JavaScript number either with
// The value of 'adjust' depends on the size of the mantissa.
Math.pow(2, exponent - adjust) * mantissa
or by directly creating an IEEE bit pattern with typed arrays.
Subnormal JavaScript numbers can be simply rounded to zero. You'll have to decide whether you want to support subnormal numbers in your 16-bit format. This will complicate the conversion process in exchange for better accuracy of numbers near zero.
You'll also have to decide whether to support infinity and NaN in your format. These values could be handled similarly to the IEEE format.
Upvotes: 2