javascript - 如何在 JavaScript 中从 ArrayBuffer / DataView 读取 64 位整数
问题描述
给定一个 64 位(8 字节)的小端ArrayBuffer
字节序,我们如何在 JavaScript 中读取 64 位整数值?
我进行了实验并想出了这个,但是鉴于DataView
尚未提供更优雅的解决方案getUint64()
吗?
const bytes = new Uint8Array([ 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff ]);
// [----- left -----] [---- right ----]
const view = new DataView(bytes.buffer);
// split 64-bit number into two 32-bit numbers
const left = view.getUint32(0, true); // 4294967295
const right = view.getUint32(4, true); // 4294967295
// combine the 2 32-bit numbers using max 32-bit val 0xffffffff
const combined = left + 2**32*right;
console.log('combined', combined);
// 18,446,744,073,709,552,000 is returned Javascript for "combined"
// 18,446,744,073,709,551,615 is max uint64 value
// some precision is lost since JS doesn't support 64-bit ints, but it's close enough
解决方案
基于原始实验和Sebastian Speitel
的建议/修复,此函数返回一个 64 位值,直到精度丢失后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;
}
测试如下:
// [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);
}
推荐阅读
- css - 网站部分的滚动动画。
- java - Selenium 项目将无法连接到 Firefox
- ios - Swift:单击推送通知操作按钮时在文本字段中写入并处理它
- angular - 将 takeUntil() 与 Observable 一起使用
? - javascript - FabricJS画布drawImage不显示图像
- php - 如何将我的 php 页面连接到远程 mongodb 服务器?
- php - 如何在php中使用curl,发布json数据和下载文件流
- doctrine - 添加基于条件的选择到学说查询构建器
- r - geom_density y 轴高于 1
- angular - 内部服务器错误。尝试使用角度和猫鼬从 mlab 中的数组中删除一个元素