Created
August 1, 2011 21:22
-
-
Save bartaz/1119041 to your computer and use it in GitHub Desktop.
Convert JavaScript number to string of 64bit double precision floating point representation (IEEE 754)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Convert a JavaScript number to IEEE-754 Double Precision | |
// value represented as an array of 8 bytes (octets) | |
// | |
// http://cautionsingularityahead.blogspot.com/2010/04/javascript-and-ieee754-redux.html | |
function toIEEE754(v, ebits, fbits) { | |
var bias = (1 << (ebits - 1)) - 1; | |
// Compute sign, exponent, fraction | |
var s, e, f; | |
if (isNaN(v)) { | |
e = (1 << bias) - 1; f = 1; s = 0; | |
} | |
else if (v === Infinity || v === -Infinity) { | |
e = (1 << bias) - 1; f = 0; s = (v < 0) ? 1 : 0; | |
} | |
else if (v === 0) { | |
e = 0; f = 0; s = (1 / v === -Infinity) ? 1 : 0; | |
} | |
else { | |
s = v < 0; | |
v = Math.abs(v); | |
if (v >= Math.pow(2, 1 - bias)) { | |
var ln = Math.min(Math.floor(Math.log(v) / Math.LN2), bias); | |
e = ln + bias; | |
f = v * Math.pow(2, fbits - ln) - Math.pow(2, fbits); | |
} | |
else { | |
e = 0; | |
f = v / Math.pow(2, 1 - bias - fbits); | |
} | |
} | |
// Pack sign, exponent, fraction | |
var i, bits = []; | |
for (i = fbits; i; i -= 1) { bits.push(f % 2 ? 1 : 0); f = Math.floor(f / 2); } | |
for (i = ebits; i; i -= 1) { bits.push(e % 2 ? 1 : 0); e = Math.floor(e / 2); } | |
bits.push(s ? 1 : 0); | |
bits.reverse(); | |
var str = bits.join(''); | |
// Bits to bytes | |
var bytes = []; | |
while (str.length) { | |
bytes.push(parseInt(str.substring(0, 8), 2)); | |
str = str.substring(8); | |
} | |
return bytes; | |
} | |
function fromIEEE754(bytes, ebits, fbits) { | |
// Bytes to bits | |
var bits = []; | |
for (var i = bytes.length; i; i -= 1) { | |
var byte = bytes[i - 1]; | |
for (var j = 8; j; j -= 1) { | |
bits.push(byte % 2 ? 1 : 0); byte = byte >> 1; | |
} | |
} | |
bits.reverse(); | |
var str = bits.join(''); | |
// Unpack sign, exponent, fraction | |
var bias = (1 << (ebits - 1)) - 1; | |
var s = parseInt(str.substring(0, 1), 2) ? -1 : 1; | |
var e = parseInt(str.substring(1, 1 + ebits), 2); | |
var f = parseInt(str.substring(1 + ebits), 2); | |
// Produce number | |
if (e === (1 << ebits) - 1) { | |
return f !== 0 ? NaN : s * Infinity; | |
} | |
else if (e > 0) { | |
return s * Math.pow(2, e - bias) * (1 + f / Math.pow(2, fbits)); | |
} | |
else if (f !== 0) { | |
return s * Math.pow(2, -(bias-1)) * (f / Math.pow(2, fbits)); | |
} | |
else { | |
return s * 0; | |
} | |
} | |
function fromIEEE754Double(b) { return fromIEEE754(b, 11, 52); } | |
function toIEEE754Double(v) { return toIEEE754(v, 11, 52); } | |
function fromIEEE754Single(b) { return fromIEEE754(b, 8, 23); } | |
function toIEEE754Single(v) { return toIEEE754(v, 8, 23); } | |
// Convert array of octets to string binary representation | |
// by bartaz | |
function toIEEE754DoubleString(v) { | |
return toIEEE754Double(v) | |
.map(function(n){ for(n = n.toString(2);n.length < 8;n="0"+n); return n }) | |
.join('') | |
.replace(/(.)(.{11})(.{52})/, "$1 $2 $3") | |
} |
could not make out for what it is worth.
nevertheless, the heritage-crime ieee 754 gave us is always really annoying when it comes to covert into decimal (god should have given us 16 or least 8 fingers), since there is no accurate math about it.
about the issue :
power function would not let you get away with an underflow when it comes to tiny numbers, so it should have been
f = ((v * Math.pow(2, - ln)-1) * Math.pow(2, fbits); in line 28 and
f = ((v * Math.pow(2, bias - 1)) * Math.pow(2, fbits); in line 32
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
this snippet is really useful, thanks :)
I had a question about
NaN
which with the above implementation is represented in octets as[ 127, 240, 0, 0, 0, 0, 0, 1 ]
however ieee754-visualization show thatNaN
is represented as[ 127, 248, 0, 0, 0, 0, 0, 0 ]
which is correct since it's usingTypedArrays
, I think that this:should be: