LoginSignup
5
2

More than 5 years have passed since last update.

(JavaScriptにおける)浮動小数点演算

Last updated at Posted at 2018-04-10

JSに限ったことではないですが、JSでも例にもれず浮動小数点演算の誤差があるようです。
普段あまり小さいな小数点気にしてないですが、仮想通貨系のプログラム書いててハマりました(桁が大きいので)。

16桁以上の大きい数字でも誤差があるようです。felisさんからコメントいただきました。

対応

  • 整数に直して計算する
  • ライブラリを使う

bignumber.jsというのを使うとよいらしいので使ってみます。他にもあるみたいです。

必要なライブラリのインストール

作業場所で、

npm install bignumber.s

実装

とりあえず、index.jsってファイルに以下を記述。

var BigNumber = require('bignumber.js');

var ans1 = 1.1 * (10**18)
var ans2 = BigNumber(1.1).times(10**18);

console.log("ans1:"+ans1);
console.log("ans2:"+ans2);

実行

node index.js

結果

bignumber.jsで処理していない方は値がおかしい

ans1:1100000000000000100
ans2:1100000000000000000

結論

小数点自体の処理、結果が少数点になることが予想される処理はbignumber.jsを利用する。

追記

16桁以上でもおかしくなると教えてもらったので検証。

var BigNumber = require('bignumber.js');

//動作1
if((1e16+ 1) === 1e16) {
    console.log("同じ1");
} else {
    console.log("同じじゃない1");
}

//表示してみる
console.log("1e16+1="+(1e16+1));

//動作2
if(new BigNumber(1e16 + 1) === 1e16){
    console.log("同じ2");
} else {
    console.log("同じじゃない2")
}

実行結果。
計算上同じに評価されるだけじゃなく、そもそも1がどっか消えてしまってます。

同じ1
1e16+1=10000000000000000
同じじゃない2

1e15で検証したら、それは問題なかったです。1e16+2だと同じにはなりません。

仮想通貨の実装では内部的にはuintとして扱い、Ethereumの仕様乗、e18以上をよく扱うので大変参考になりました。JSが正しく計算できるのは2の53乗まで。web3.jsは内部的にbignumber.jsを利用してるようですが、素で計算するときは注意が必要です。

5
2
1

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
5
2