请教:如何使用JavaScript读取二进制文件内的“半精度Float”(也叫作half-precision float或Float16)数值?
路过的大侠们救救我呀。 我正在使用 jDataView + jBinary 的库组合 拆包/解析 二进制矢量图型文件(类似于MVT格式,就是压缩率比MVT还高)。我遇到的问题是,图形矢量文件内保存的坐标信息都以“半精度Float”(也叫作half-precision float或Float16)类型存储的。 我目前使用jBinary的read(‘uint16’)的API把16bit的值给读了出来(这样可以确保后面的数据能够被位对齐地继续正确地读取),但是,这个读出来是“整型数”,不是我想要的Float16。
我想请教,我接下来,如何对那个被读出来的临时的 uint16数值 进行 位操作 转换出 我需要的 “Float16”?
3 回复
写了个转换的方法 https://en.wikipedia.org/wiki/Half-precision_floating-point_format
var float16 = function (n) {
n = n & 0xffff;
var sign = n >> 15;
sign = sign ? -1 : 1;
var exponent = (n >> 10) & 0x1f;
var fraction = n & 0x3ff;
var fr = 1;
if (exponent == 0x1f) {
return fraction == 0 ? sign * Infinity : NaN;
} else if (exponent == 0) {
fr = 0;
exponent = -14;
} else {
exponent = exponent - 0xf;
}
for (var i = 0; i < 10; i++) {
fr += ((fraction >> (10 - i -1)) & 0x1) * Math.pow(1/2, i + 1);
}
return sign * fr * Math.pow(2, exponent);
};
console.log(float16(0x3c00), 1);
console.log(float16(0x3c01), 1.0009765625);
console.log(float16(0xc000), -2);
console.log(float16(0x7bff), 65504);
console.log(float16(0x0400), '6.10352 × 10−5');
console.log(float16(0x03ff), '6.09756 × 10−5');
console.log(float16(0x0001), '5.96046 × 10−8');
console.log(float16(0x0000), '0');
console.log(float16(0x8000), '-0');
console.log(float16(0x7c00), Infinity);
console.log(float16(0xfc00), -Infinity);
console.log(float16(0x3555), 0.333251953125);
本以为是一个简单的事,其实不是:
var cmsb = function(n) {
var e = 0;
if (n > 0xff) {n >>= 8; e += 8;}
if (n > 0xf) {n >>= 4; e += 4;}
if (n > 0x3) {n >>= 2; e += 2;}
e += n >> 1;
return e;
}
var float16 = function (n) {
n = n & 0xffff;
var sign = n >> 15 & 0x1
var exp = n >> 10 & 0x1f;
var faction = n & 0x3ff;
if (exp == 0) {
if (faction > 0) {
var m = 10 - cmsb(faction);
faction = faction << m & 0x3ff;
exp = 113 - m;
}
} else if (exp == 31) {
exp = 255;
} else {
exp += 127 - 15;
}
console.log("=>", sign, exp, faction)
var buffer = new ArrayBuffer(4);
var ints = new Uint32Array(buffer);
ints[0] = sign << 31 | exp << 23 | faction << 13;
return new Float32Array(buffer)[0];
};
console.log(float16(0x7c80), NaN);
console.log(float16(0x3c00), 1);
console.log(float16(0x3c01), 1.0009765625);
console.log(float16(0xc000), -2);
console.log(float16(0x7bff), 65504);
console.log(float16(0x0400), '6.10352E-5');
console.log(float16(0x03ff), '6.09756E-5');
console.log(float16(0x0001), '5.96046E-8');
console.log(float16(0x0000), '0');
console.log(float16(0x8000), '-0');
console.log(float16(0x7c00), Infinity);
console.log(float16(0xfc00), -Infinity);
console.log(float16(0x3555), 0.333251953125);
@hl4 谢谢大神呀。在我同一个项目里,又遇到了另一个棘手的问题:https://cnodejs.org/topic/585f421b708f21aa5db0eccf 。大神能不能也提供我一些线索呀?