How to Read 64-bit Integer from an ArrayBuffer / DataView in JavaScript

后端 未结 2 564
深忆病人
深忆病人 2020-12-17 06:21

Given a 64-bit (8-byte) little-endian ArrayBuffer of bytes, how can we read 64-bit integer values in JavaScript?

I experimented and came up with this, b

2条回答
  •  [愿得一人]
    2020-12-17 06:30

    Based on the original experiment and Sebastian Speitel's suggestion/fix, this function returns a 64-bit value until precision is lost after Number.MAX_SAFE_INTEGER

    DataView.prototype.getUint64 = function(byteOffset, littleEndian) {
      // split 64-bit number into two 32-bit parts
      const left =  this.getUint32(byteOffset, littleEndian);
      const right = this.getUint32(byteOffset+4, littleEndian);
    
      // combine the two 32-bit values
      const combined = littleEndian? left + 2**32*right : 2**32*left + right;
    
      if (!Number.isSafeInteger(combined))
        console.warn(combined, 'exceeds MAX_SAFE_INTEGER. Precision may be lost');
    
      return combined;
    }
    


    Tested below:

    // [byteArray, littleEndian, expectedValue]
    const testValues = [
      // big-endian
      [new Uint8Array([0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0xff]),  false, 255], 
      [new Uint8Array([0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0xff, 0xff]),  false, 65535],
      [new Uint8Array([0x00, 0x00, 0x00, 0x00,  0xff, 0xff, 0xff, 0xff]),  false, 4294967295],
      [new Uint8Array([0x00, 0x00, 0x00, 0x01,  0x00, 0x00, 0x00, 0x00]),  false, 4294967296],
      [new Uint8Array([0x00, 0x1f, 0xff, 0xff,  0xff, 0xff, 0xff, 0xff]),  false, 9007199254740991], // maximum precision
      [new Uint8Array([0x00, 0x20, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00]),  false, 9007199254740992], // precision lost
      [new Uint8Array([0x00, 0x20, 0x00, 0x00,  0x00, 0x00, 0x00, 0x01]),  false, 9007199254740992], // precision lost
    
      // little-endian
      [new Uint8Array([0xff, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00]),  true, 255], 
      [new Uint8Array([0xff, 0xff, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00]),  true, 65535],
      [new Uint8Array([0xff, 0xff, 0xff, 0xff,  0x00, 0x00, 0x00, 0x00]),  true, 4294967295],
      [new Uint8Array([0x00, 0x00, 0x00, 0x00,  0x01, 0x00, 0x00, 0x00]),  true, 4294967296],
      [new Uint8Array([0x00, 0x00, 0x00, 0x00,  0x00, 0x01, 0x00, 0x00]),  true, 1099511627776],
      [new Uint8Array([0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x01, 0x00]),  true, 281474976710656],
      [new Uint8Array([0xff, 0xff, 0xff, 0xff,  0xff, 0xff, 0x1f, 0x00]),  true, 9007199254740991], // maximum precision
    ];
    
    testValues.forEach(testGetUint64);
    
    function testGetUint64([bytes, littleEndian, expectedValue]) {
      const val = new DataView(bytes.buffer).getUint64(0, littleEndian);
      console.log(val === expectedValue? 'pass' : 'FAIL. expected '+expectedValue+', received '+val);
    }
    

提交回复
热议问题