2010-12-10 61 views
19

有没有什么办法可以读取JS中浮点值的字节?我需要的是将原始FLOAT或DOUBLE值写入我需要的某种二进制格式,那么是否有任何方法可以获得逐字节的IEEE 754表示?当然,写作也是一样的问题。在JS中浮点的读/写字节

回答

4

请问this snippet有帮助吗?

@Kevin Gadd

var parser = new BinaryParser 
    ,forty = parser.encodeFloat(40.0,2,8) 
    ,twenty = parser.encodeFloat(20.0,2,8); 
console.log(parser.decodeFloat(forty,2,8).toFixed(1)); //=> 40.0 
console.log(parser.decodeFloat(twenty,2,8).toFixed(1)); //=> 20.0 
+1

+1这很不错 – Zevan 2010-12-11 02:13:41

+0

非常好!这看起来正是我需要的。 – 2010-12-11 09:19:02

+4

该代码段中使用的算法被彻底破坏。当用于读取浮动或双打时,它会失败。 例如,它将40.0读作32.0,将20.0读作16.0。 – 2012-03-25 10:38:10

0

我希望你能弄清楚(blech),但我假设你问是否有内置的东西。还没有我听过的;请参阅the spec的第8.5节和第15.7节。

3

Koolinc的片段是好,如果你需要一个解决方案,强大的,但如果你需要它的有限使用你最好写你自己的代码。我写了下面的功能字节的字符串十六进制表示转换为float:

function decodeFloat(data) { 
    var binary = parseInt(data, 16).toString(2); 
    if (binary.length < 32) 
     binary = ('00000000000000000000000000000000'+binary).substr(binary.length); 
    var sign = (binary.charAt(0) == '1')?-1:1; 
    var exponent = parseInt(binary.substr(1, 8), 2) - 127; 
    var significandBase = binary.substr(9); 
    var significandBin = '1'+significandBase; 
    var i = 0; 
    var val = 1; 
    var significand = 0; 

    if (exponent == -127) { 
     if (significandBase.indexOf('1') == -1) 
      return 0; 
     else { 
      exponent = -126; 
      significandBin = '0'+significandBase; 
     } 
    } 

    while (i < significandBin.length) { 
     significand += val * parseInt(significandBin.charAt(i)); 
     val = val/2; 
     i++; 
    } 

    return sign * significand * Math.pow(2, exponent); 
} 

有用来在两个方向浮动在维基百科上的点的所有格式转换算法的详细说明,而且很容易用这些编写你自己的代码。从数字转换为字节应该更加困难,因为您需要首先对数字进行归一化。

+2

我已经扩展了这个解决方案来处理64位浮点数和小端编码。它还需要一个字节数组而不是base-16字符串(这样64位浮点数可以正常工作而不会产生舍入问题)。 https://gist.github.com/2192799 – 2012-03-25 10:53:38

35

你可以用typed arrays做到这一点:

var buffer = new ArrayBuffer(4); 
var intView = new Int32Array(buffer); 
var floatView = new Float32Array(buffer); 

floatView[0] = Math.PI 
console.log(intView[0].toString(2)); //bits of the 32 bit float 

或者另一种方式:

var view = new DataView(new ArrayBuffer(4)); 
view.setFloat32(0, Math.PI); 
console.log(view.getInt32(0).toString(2)); //bits of the 32 bit float 

不知道什么是浏览器的支持等等,虽然

+3

Cool,TIL'Double'在JavaScript中被称为'Float64'。我正在寻找'DoubleArray' - 无济于事 - 但是'Float64Array'存在并且对我来说很有用 – 2013-03-01 07:28:37

+1

请注意,这是*不支持的IE9! – Qix 2014-09-17 00:14:42

+1

它看起来像你可以使用'Uint8Array'(至少在Chrome中)而不是'Int32Array'来更容易地得到单独的字节 – 2017-04-07 19:42:19

6

我创建米洛斯的扩张解决方案,应该有点快,假设TypedArrays当然不是一个选项(在我的情况下,我正在与他们不可用的环境):

function Bytes2Float32(bytes) { 
    var sign = (bytes & 0x80000000) ? -1 : 1; 
    var exponent = ((bytes >> 23) & 0xFF) - 127; 
    var significand = (bytes & ~(-1 << 23)); 

    if (exponent == 128) 
     return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY); 

    if (exponent == -127) { 
     if (significand == 0) return sign * 0.0; 
     exponent = -126; 
     significand /= (1 << 22); 
    } else significand = (significand | (1 << 23))/(1 << 23); 

    return sign * significand * Math.pow(2, exponent); 
} 

给定一个包含4个字节的整数,包含一个IEEE-754 32位单精度浮点数,这将产生(大致)正确的Javascript数值而不使用任何循环。

+1

'if(significantand == 0)return sign * 0.0;' - 肯定任何时间为零的是......零? “-1 * 0.0”是否产生负零? – Nick 2013-10-22 22:13:38

+0

@Nick:是的,它确实 – Eric 2014-11-22 10:04:46

+0

@Haravikk,获取数字的位表示法怎么样? – Pacerier 2017-04-17 18:39:16

1

我有一个类似的问题,我想将任何javascript数字转换为一个缓冲区,然后解析它,而不会将其字符串化。

function numberToBuffer(num) { 
    const buf = new Buffer(8) 
    buf.writeDoubleLE(num, 0) 
    return buf 
} 

使用例如:

// convert a number to buffer 
const buf = numberToBuffer(3.14) 
// and then from a Buffer 
buf.readDoubleLE(0) === 3.14 

这适用于当前节点LTS(4.3.1)及以上。没有在较低版本中测试。

+0

我可以证实,这也适用于Node.js 0.10.40。使用旧版本的Node-RED(0.11.1),我显然无法访问Float32Array,所以您的解决方案对我来说是唯一的解决方案! 我使用'新的缓冲区(阵列)'从4字节的二进制浮点数组和buffer.readFloatBE(0)来创建缓冲区来检索浮点数。 – winne2 2017-01-06 16:47:06