请教:如何使用JavaScript读取二进制文件内的"半精度Float"(也叫作half-precision float或Float16)数值? - CNode技术社区

请教:如何使用JavaScript读取二进制文件内的"半精度Float"(也叫作half-precision float或Float16)数值?
发布于 9 年前 作者 stuartZhang 5726 次浏览 来自 问答

路过的大侠们救救我呀。 我正在使用 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 。大神能不能也提供我一些线索呀?

回到顶部

AltStyle によって変換されたページ (->オリジナル) /