8

さて、私は Float32Array などの型付き配列にアクセスできないというかなり厄介な状況ですが、それでも Javascript 数値をバイトに変換できる必要があります。さて、問題なく処理できる整数ですが、浮動小数点値に対してそれを行う方法がわかりません。

逆の方法(バイトを浮動小数点数に変換)の問題は解決しましたが、浮動小数点数からバイトへの変換に関するドキュメントはほとんどありません。ほとんどの言語では、ポインターを読み取ったり、それを処理するための共通クラスを使用したりできるためです。

理想的には、float を 4 バイトと 8 バイトの両方の表現に変換し、どちらを使用するかを選択できるようにしたいと考えています。ただし、単純に数値を取り、それを 8 バイトとして吐き出すことができるコードは、おそらくそこから自分で 32 ビット バージョンを思い付くことができるので、依然として優れています。

4

3 に答える 3

8

さて、実際にそれを理解したので、単精度と倍精度のソリューションを共有します。現在、それらが 100% 標準に準拠しているとは保証できませんが、ループを必要とせず、問題なく動作するようです:

単精度 (10 進値が与えられた場合、2 進数表現で 1 つの 32 ビット ビッグ エンディアン整数が出力されます):

function toFloat32(value) {
    var bytes = 0;
    switch (value) {
        case Number.POSITIVE_INFINITY: bytes = 0x7F800000; break;
        case Number.NEGATIVE_INFINITY: bytes = 0xFF800000; break;
        case +0.0: bytes = 0x40000000; break;
        case -0.0: bytes = 0xC0000000; break;
        default:
            if (Number.isNaN(value)) { bytes = 0x7FC00000; break; }

            if (value <= -0.0) {
                bytes = 0x80000000;
                value = -value;
            }

            var exponent = Math.floor(Math.log(value) / Math.log(2));
            var significand = ((value / Math.pow(2, exponent)) * 0x00800000) | 0;

            exponent += 127;
            if (exponent >= 0xFF) {
                exponent = 0xFF;
                significand = 0;
            } else if (exponent < 0) exponent = 0;

            bytes = bytes | (exponent << 23);
            bytes = bytes | (significand & ~(-1 << 23));
        break;
    }
    return bytes;
};

倍精度 (10 進値が 2 つの 32 ビット整数をビッグエンディアン順のバイナリ表現で出力する場合):

function toFloat64(value) {
    if ((byteOffset + 8) > this.byteLength) 
        throw "Invalid byteOffset: Cannot write beyond view boundaries.";

    var hiWord = 0, loWord = 0;
    switch (value) {
        case Number.POSITIVE_INFINITY: hiWord = 0x7FF00000; break;
        case Number.NEGATIVE_INFINITY: hiWord = 0xFFF00000; break;
        case +0.0: hiWord = 0x40000000; break;
        case -0.0: hiWord = 0xC0000000; break;
        default:
            if (Number.isNaN(value)) { hiWord = 0x7FF80000; break; }

            if (value <= -0.0) {
                hiWord = 0x80000000;
                value = -value;
            }

            var exponent = Math.floor(Math.log(value) / Math.log(2));
            var significand = Math.floor((value / Math.pow(2, exponent)) * Math.pow(2, 52));

            loWord = significand & 0xFFFFFFFF;
            significand /= Math.pow(2, 32);

            exponent += 1023;
            if (exponent >= 0x7FF) {
                exponent = 0x7FF;
                significand = 0;
            } else if (exponent < 0) exponent = 0;

            hiWord = hiWord | (exponent << 20);
            hiWord = hiWord | (significand & ~(-1 << 20));
        break;
    }

    return [hiWord, loWord];
};

コピー/貼り付けの間違いをお詫びします。また、コードはエンディアンの処理を省略していますが、追加はかなり簡単です。

提案を投稿してくれた皆さんに感謝しますが、速度を上げるためにできるだけループを避けたかったので、ほとんど自分で考え出すことになりました。それはまだ正確に猛烈に速いわけではありませんが、そうするでしょう =)

于 2013-04-16T17:23:34.387 に答える
1

http://ysangkok.github.io/IEEE-754/index.xhtmlにあるような IEEE 754 の JavaScript 実装を使用できます。Emscripten と gmp.js を使用します。

于 2014-01-16T17:04:18.683 に答える
1

ここでBinaryParser.encodeFloat を参照してください。

于 2013-04-10T20:37:49.510 に答える