在 JavaScript 中将大整数转换为 8 字节数组

Converting large integer to 8 byte array in JavaScript

本文关键字:字节 字节数 数组 转换 整数 JavaScript      更新时间:2023-09-26

我正在尝试在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

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

由于您要从十进制转换为字节,因此除以 256 是一种通过将字符串中的数字拆分为部分来轻松模拟的操作。 我们可以利用两个数学规则。

  1. 十进制数最右边的 n 位数字可以确定 2^n 的整除性。
  2. 10^n 将始终能被 2^n 整除。

因此,我们可以取数字并拆分最右边的 8 位数字以找到余数(即 & 255),将右侧部分除以 256,然后将数字的左侧部分分别除以 256。 左边的余数可以通过公式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移动到数字的右部(最右边的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]

您的值和最大的 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()

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));
   }
}

或者接近那个...