4

我正在尝试将一个大数字转换为 javascript 中的 8 字节数组。

这是我传入的 IMEI:45035997012373300

var bytes = new Array(7);
for(var k=0;k<8;k++) {
  bytes[k] = value & (255);
  value = value / 256;
}

这最终给出了字节数组:48,47,7,44,0,0,160,0。转换回long,值为45035997012373296,比正确值小4。

知道为什么会这样以及如何修复它以序列化为正确的字节吗?

4

3 回答 3

3

由于您正在从十进制转换为字节,因此除以 256 是一个非常容易模拟的操作,可以通过将字符串中的数字分成几部分来模拟。我们可以利用两个数学规则。

  1. 十进制数的最右边 n 位可以确定可被 2^n 整除。
  2. 10^n 总是能被 2^n 整除。

因此,我们可以将这个数字从最右边的 8 位数字中分离出来以找到余数(即& 255),将右边的部分除以 256,然后将数字的左边部分分别除以 256。左边的余数可以通过公式 移到数字的右边(最右边的 8 位)n*10^8 \ 256 = (q*256+r)*10^8 \ 256 = q*256*10^8\256 + r*10^8\256 = q*10^8 + r*5^8,其中\是整数除法,qr分别是商和余数n \ 256。这产生了以下方法,对长度不超过 23 位(15 正常 JS 精度 + 8 额外产生的此方法)的字符串进行整数除以 256:

function divide256(n)
{
    if (n.length <= 8)
    {
        return (Math.floor(parseInt(n) / 256)).toString();
    }
    else
    {
        var top = n.substring(0, n.length - 8);
        var bottom = n.substring(n.length - 8);
        var topVal = Math.floor(parseInt(top) / 256);
        var bottomVal = Math.floor(parseInt(bottom) / 256);
        var rem = (100000000 / 256) * (parseInt(top) % 256);
        bottomVal += rem;
        topVal += Math.floor(bottomVal / 100000000); // shift back possible carry
        bottomVal %= 100000000;
        if (topVal == 0) return bottomVal.toString();
        else return topVal.toString() + bottomVal.toString();
    }
}

从技术上讲,这可以实现为将任意大小的整数除以 256,只需将数字递归地分成 8 位部分并使用相同的方法分别处理每个部分的除法。

45035997012373300这是一个为您的示例编号 ( )计算正确字节数组的工作实现:http: //jsfiddle.net/kkX2U/

[52, 47, 7, 44, 0, 0, 160, 0]
于 2012-04-20T21:52:46.080 回答
2

你的值和最大的 JavaScript 整数比较:

45035997012373300  // Yours
 9007199254740992  // JavaScript's biggest integer

JavaScript 不能将您的原始值完全表示为整数;这就是为什么你的脚本分解它会给你一个不精确的表示。

有关的:

var diff = 45035997012373300 - 45035997012373298;
// 0 (not 2)

编辑:如果您可以将您的号码表示为十六进制字符串:

function bytesFromHex(str,pad){
  if (str.length%2) str="0"+str;
  var bytes = str.match(/../g).map(function(s){
    return parseInt(s,16);
  });
  if (pad) for (var i=bytes.length;i<pad;++i) bytes.unshift(0);
  return bytes;
}

var imei = "a000002c072f34";
var bytes = bytesFromHex(imei,8);
// [0,160,0,0,44,7,47,52]

如果您需要从最不重要到最重要的字节排序,请.reverse()在结果上抛出 a。

于 2012-04-20T21:15:05.277 回答
0

将imei存储为十六进制字符串(如果可以的话),然后以这种方式解析字符串,这样您可以在构建数组时保持精度。如果这个问题没有得到解答,当我回到家使用我的普通电脑时,我会带着 PoC 回来。

就像是:

function parseHexString(str){
   for (var i=0, j=0; i<str.length; i+=2, j++){
      array[j] = parseInt("0x"+str.substr(i, 2));
   }
}

或接近那个...

于 2012-04-20T21:44:25.887 回答