最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Decompressing Half Precision Floats in Javascript - Stack Overflow

programmeradmin11浏览0评论

I'm trying to read a binary file with javascript that contains a lot of 16-bit floating point numbers. Fairly certain it's IEEE standard, little endian. It's pretty straightforward to read the two bytes into an int, but from there I'm not having much success expanding that out into a full floating point number. Any clues?

I'm trying to read a binary file with javascript that contains a lot of 16-bit floating point numbers. Fairly certain it's IEEE standard, little endian. It's pretty straightforward to read the two bytes into an int, but from there I'm not having much success expanding that out into a full floating point number. Any clues?

Share Improve this question asked Apr 15, 2011 at 14:44 TojiToji 34.5k22 gold badges108 silver badges119 bronze badges
Add a comment  | 

4 Answers 4

Reset to default 11

@Toji: Thanks a lot! Here a version with optimizations for NON high-end-engines like V8

var pow = Math.pow;
function decodeFloat16 (binary) {"use strict";
    var exponent = (binary & 0x7C00) >> 10,
        fraction = binary & 0x03FF;
    return (binary >> 15 ? -1 : 1) * (
        exponent ?
        (
            exponent === 0x1F ?
            fraction ? NaN : Infinity :
            pow(2, exponent - 15) * (1 + fraction / 0x400)
        ) :
        6.103515625e-5 * (fraction / 0x400)
    );
};

And a more complete IEEE 754 test:

function test() {
    var samples = [
        0x3C00, // = 1
            0xC000, // = −2
            0x7BFF, // = 6.5504 × 10^4 (max half precision)
            0x0400, // = 2^−14 ≈ 6.10352 × 10^−5 (minimum positive normal)
            0x0001, // = 2^−24 ≈ 5.96046 × 10^−8 (minimum strictly positive subnormal)
            0x0000, // = 0
            0x8000, // = −0
            0x7C00, // = Infinity
            0xFC00, // = −Infinity
            0x3555, // ≈ 0.33325... ≈ 1/3
            0x7C01  // = NaN
        ],
        i = samples.length;
    while (i--) samples[i] = decodeFloat16(samples[i]);
    return samples.join("\n");
};

Performance test results compared with the original code from Toji:

  • Chrome 17: +30 %
  • Safari 5.1: -10 % (don't ask me why)
  • Firefox 9: +11 %
  • IExplorer 9: +22 %
  • IExplorer 7: +14 %

I ended up implementing my own parser based on the information on the Wikipedia page. It's probably not the fastest out there, but I'm not too concerned about that. Here it is for those that are curious:

function float16_to_float(h) {
    var s = (h & 0x8000) >> 15;
    var e = (h & 0x7C00) >> 10;
    var f = h & 0x03FF;

    if(e == 0) {
        return (s?-1:1) * Math.pow(2,-14) * (f/Math.pow(2, 10));
    } else if (e == 0x1F) {
        return f?NaN:((s?-1:1)*Infinity);
    }

    return (s?-1:1) * Math.pow(2, e-15) * (1+(f/Math.pow(2, 10)));
}

function test() {
    float16_to_float(parseInt('3C00', 16)); // 1
    float16_to_float(parseInt('C000', 16)); // -2

    float16_to_float(parseInt('7BFF', 16)); // 6.5504 × 10^4 (Maximum half precision)
    float16_to_float(parseInt('3555', 16)); // 0.33325... ≈ 1/3
    // Works with all the test cases on the wikipedia page
}

Take inspiration from jspack. A bunch of people tried similar stuff before.

Begin reading this wikipedia article. For implementation, I'd create a lookup table. (or maybe two, one for high and low byte.

发布评论

评论列表(0)

  1. 暂无评论