简体   繁体   English

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

[英]Converting large integer to 8 byte array in JavaScript

I'm trying to convert a large number into an 8 byte array in javascript. 我正在尝试将大量数字转换为javascript中的8字节数组。

Here is an IMEI that I am passing in: 45035997012373300 这是我传递的IMEI:45035997012373300

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

This ends up giving the byte array: 48,47,7,44,0,0,160,0. 这最终给出了字节数组:48,47,7,44,0,0,160,0。 Converted back to a long, the value is 45035997012373296, which is 4 less than the correct value. 转换回long,值为45035997012373296,比正确值小4。

Any idea why this is and how I can fix it to serialize into the correct bytes? 知道这是为什么以及如何修复它以序列化到正确的字节?

Since you are converting from decimal to bytes, dividing by 256 is an operation that is pretty easily simulated by splitting up a number in a string into parts. 由于您要从十进制转换为字节,因此除以256是通过将字符串中的数字拆分为多个部分而非常容易模拟的操作。 There are two mathematical rules that we can take advantage of. 我们可以利用两个数学规则。

  1. The right-most n digits of a decimal number can determine divisibility by 2^n. 十进制数的最右边的n位数可以确定2 ^ n的可分性。
  2. 10^n will always be divisible by 2^n. 10 ^ n将始终可被2 ^ n整除。

Thus we can take the number and split off the right-most 8 digits to find the remainder (ie, & 255 ), divide the right part by 256, and then also divide the left part of the number by 256 separately. 因此,我们可以取数字并拆分最右边的8位数来找到余数(即& 255 ),将右边的部分除以256,然后再将数字的左边部分分开256。 The remainder from the left part can be shifted into the right part of the number (the right-most 8 digits) by the formula 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 , where \\ is integer division and q and r are quotient and remainder, respectively for n \\ 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位数) 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商和余数。 This yields the following method to do integer division by 256 for strings of up to 23 digits (15 normal JS precision + 8 extra yielded by this method) in length: 这产生了以下方法:对于长度为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();
    }
}

Technically this could be implemented to divide an integer of any arbitrary size by 256, simply by recursively breaking the number into 8-digit parts and handling the division of each part separately using the same method. 从技术上讲,这可以实现将任意大小的整数除以256,简单地通过递归地将数字分成8位数部分并使用相同的方法分别处理每个部分的划分。

Here is a working implementation that calculates the correct byte array for your example number ( 45035997012373300 ): http://jsfiddle.net/kkX2U/ . 这是一个工作实现,为您的示例编号计算正确的字节数组( 45035997012373300 ): http//jsfiddle.net/kkX2U/

[52, 47, 7, 44, 0, 0, 160, 0]

Your value and the largest JavaScript integer compared: 您的值和最大的JavaScript整数比较:

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

JavaScript cannot represent your original value exactly as an integer; JavaScript不能完全以整数表示原始值; that's why your script breaking it down gives you an inexact representation. 这就是为什么你的脚本分解它会给你一个不精确的表示。

Related: 有关:

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

Edit : If you can express your number as a hexadecimal string: 编辑 :如果您可以将您的数字表示为十六进制字符串:

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]

If you need the bytes ordered from least-to-most significant, throw a .reverse() on the result. 如果您需要从最小到最重要的顺序排序的字节,请在结果上抛出.reverse()

store the imei as a hex string (if you can), then parse the string in that manner, this way you can keep the precision when you build the array. 将imei存储为十六进制字符串(如果可以的话),然后以这种方式解析字符串,这样就可以在构建数组时保持精度。 I will be back with a PoC when i get home on my regular computer, if this question has not been answered. 如果这个问题没有得到解答,当我回到常规计算机上时,我将回到PoC。

something like: 就像是:

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

or close to that whatever... 或者接近那个......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM