如何将两个小数组合成一个大端?

时间:2017-11-23 18:41:27

标签: node.js endianness bigint

我有两个整数,如1511461841253093752,表示自unix时代以来的秒+纳秒。

如何将它们组合成一个大端Buffer

1511461841253093752太大而无法存储为数字,这使得这个棘手且简单地连接两个UInt32BE缓冲区也不正确。

(很明显,我想编码1511461841253093752不是两个单独的整数)

1511461841253093752的日志库2是60.4,因此结果应该是8个字节。

我可以通过执行253093752%256来获得第一个(最右边)字节,但我无法弄清楚如何在不使用bigint库的情况下获取第二个字节。这不可能吗?

2 个答案:

答案 0 :(得分:1)

我认为这段代码,使用big-integer 模块,执行您的要求。我添加了一些评论来解释 发生了什么。

// Load a module to represent big integers in javascript
var bigInt = require("big-integer");

// The value that we want to represent as big endian
var num = bigInt("1511461841253093752", 10);

// First we're going to store the bytes of this value in
// little endian order
var values = [];
while (num.compare(bigInt.zero) != 0) {
    values.push(num.mod("256").valueOf());
    num = num.divide("256");
}

// Fill with zeros if needed. 
var desiredLength = 8;
while (values.length < desiredLength) {
    values.push(0);
}

// Reverse the order to get big endian order and create
// a buffer from the array
values = values.reverse();
var buf = Buffer.from(values);

// This outputs <Buffer 14 f9 ca 89 5b 72 d1 78>
console.log(buf);

答案 1 :(得分:0)

我使用big-integer库作为brm suggested在Node.js和浏览器JS中实现了这一点。

节点

function uuid() {
    const [sec,ns] = getTime(); 

    let num = BigInt(sec + padNano(ns));

    let {quotient,remainder} = num.divmod(4294967296);

    let buf = Buffer.allocUnsafe(16);
    buf.writeUInt32BE(quotient.valueOf(),0,true);
    buf.writeUInt32BE(remainder.valueOf(),4,true);
    Crypto.randomBytes(8).copy(buf, 8);

    return buf;
}


function padNano(ns) {
    let padLen = 9 - ns.length;
    if(padLen > 0) {
        return '000000000'.slice(0,padLen) + ns;
    }
    return String(ns);
}

浏览器

export default function uuid() {
    const [sec,ns] = getTime();

    let num = BigInt(sec + String(ns).padStart(9,'0'));

    let {quotient,remainder} = num.divmod(4294967296);

    let buf = new ArrayBuffer(16);
    let dataView = new DataView(buf,0,8);
    dataView.setUint32(0, quotient.valueOf(), false);
    dataView.setUint32(4, remainder.valueOf(), false);

    let cryptView = new Uint8Array(buf, 8, 8);
    crypto.getRandomValues(cryptView);

    return buf;
}

详细信息

正如我在问题中提到的,数字代表秒和纳秒。 1e9纳秒= 1秒,因此正确的数字上限为999999999,最多需要30位才能表示。

我没有对我的问题中的“秒”进行限制,但我们可以将它限制在32位以使数学更简单。 Unix纪元+ 2 64 纳秒= 2554年7月21日,这对于我的目的来说远远不够。

因此两个数字整齐地适合uint32。所以我们所要做的就是将它除以2 32 。左半部分是商,右半部分是余数。我们可以在两个操作中执行此操作,但是大整数对于已经称为divmod的函数有一个方便的功能,所以我使用了它。

接下来,我们只需要使用big-endian将这两个部分写入缓冲区。幸运的是,浏览器和Node都有这方面的功能,所以我们只用两次写就可以做到。