我需要将一个Coordinate值(一个float)转换为一个protobuf对象以发送到服务器 问题是我需要将其转换为fixed64对象, 这是一个64位长,javascript不长时间支持数字。
我正在使用this库来创建我的protobuf缓冲区。 我找到了一个解决相同问题的工作python片段
def f2i(float):
return struct.unpack('<Q', struct.pack('<d', float))[0]
这使用了struct库,实际上将float转换为二进制,然后再转换为long。 我需要获得相同的输出
所以51.366805将成为4632426052430037296
失去一点精度不是最大的问题,我只需要转换值
答案 0 :(得分:1)
正如您所提到的,JS不支持64位整数,因此您将无法获得相同的输出。您可以得到的最接近的是两个32位整数,它们代表相同的64位整数,根据您的Protobuf库期望的输入类型,这可能有效,也可能无效。
我建议在this question的接受答案中查看toFloat64()函数。
以下是略微简化的版本:
function toFloat64(value) {
var hiWord = 0, loWord = 0;
if (value <= -0.0) {
hiWord = 0x80000000;
value = -value;
}
var exponent = Math.floor(Math.log(value) / Math.log(2));
var significand = Math.floor((value / Math.pow(2, exponent)) * Math.pow(2, 52));
loWord = significand & 0xFFFFFFFF;
significand /= Math.pow(2, 32);
exponent += 1023;
if (exponent >= 0x7FF) {
exponent = 0x7FF;
significand = 0;
} else if (exponent < 0) exponent = 0;
hiWord = hiWord | (exponent << 20);
hiWord = hiWord | (significand & ~(-1 << 20));
return [hiWord, loWord];
}
我们试一试:
var res = toFloat64(51.366805),
hexHi = ('0000000' + res[0].toString(16)).substr(-8, 8),
hexLo = ('0000000' + res[1].toString(16)).substr(-8, 8);
console.log('32-bit high word = 0x' + hexHi);
console.log('32-bit low word = 0x' + hexLo);
console.log('64-bit result = 0x' + hexHi + hexLo);
输出:
32-bit high word = 0x4049aef3
32-bit low word = 0x775b8130
64-bit result = 0x4049aef3775b8130
其中0x4049aef3775b8130确实是4632426052430037296一旦转换回十进制。
如果你真的需要原子JS编号,你的最后一个选择是将它转换回53位精度的整数:
var int53 = parseInt(hexHi + hexLo, 16);
console.log(int53);
输出:
4632426052430037000