将坐标值转换为fixed64 protobuf对象

时间:2016-07-16 19:39:26

标签: javascript python node.js protocol-buffers

我需要将一个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

失去一点精度不是最大的问题,我只需要转换值

1 个答案:

答案 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