LoginSignup
11
9

More than 3 years have passed since last update.

JavaScriptの浮動小数点数を符号なし64ビット整数で表現したい

Last updated at Posted at 2020-04-05

はじめに

JavaScriptにおける数値は、倍精度浮動小数点数しかないわけですが、倍精度浮動小数点数を構成するビット列を符号なし64ビット整数で表現した値が欲しいという場面がありました。このやり方について調べたので、記事にしてみました。

変換方法

function DoubleToBigInt(f)
{
  var buf = new ArrayBuffer(8);
  (new Float64Array(buf))[0] = f;

  lower = BigInt((new Uint32Array(buf))[0]);
  upper = BigInt((new Uint32Array(buf))[1]);

  return (upper << BigInt(32)) | lower;
}

上記のコードでは、ArrayBufferを経由して、倍精度浮動小数点数から2つの符号なし32ビット整数に変換しています。upperは倍精度浮動小数点数の上位32ビット、lowerは倍精度浮動小数点数の下位32ビットです。残念ながら、Uint64Arrayなんてものはありませんから、こうするしかないですね…

2つの符号なし32ビット整数に変換した後は、これらの値をBitIntに変換して符号なし64ビット整数の値を表現しています。

この関数の戻り値を確認してみましょう。


var f = 0.1234567;
console.log(DoubleToBigInt(f)); // 4593560413433027186n

4593560413433027186という値になりましたが、これが正しいのかC言語のコードで検証してみます。

#include <stdio.h>

union {
  double d;
  unsigned long l;
} val;

int main(void) {
  val.d = 0.1234567;
  printf("%ld\n", val.l);
  return 0;
}

上記のコードをコンパイルして、実行してみます。

$ gcc test.c
$ ./a.out
4593560413433027186

JavaScriptコード側の出力と一致しました。

おわりに

これをやろうと思ったのは、ももテクの記事を参考にJavaScriptのMath.random関数(XorShift128+)の内部状態を復元しようとしたためです。浮動小数点数表現で出力されるよりは、整数値で出力された方が解析しやすいかなと思いました。

なにはともあれ、上記のコードで浮動小数点数 -> 符号なし64ビット整数への変換ができたので、一件落着です。

追記 (2020/04/05 15:38)

@uhyo さんからBigUint64Arrayの存在を教えていただきました。ありがとうございます!BigUint64Arrayを使えば、DoubleToBigInt関数を以下のようにもっと簡潔に書けます。

function DoubleToBigInt(f)
{
  var buf = new ArrayBuffer(8);
  (new Float64Array(buf))[0] = f;

  return (new BigUint64Array(buf))[0];
}

参考サイト

https://stackoverflow.com/questions/2003493/javascript-float-from-to-bits
https://qiita.com/uhyo/items/f9abb94bcc0374d7ed23

11
9
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9