俺の開発大作戦

Linux, Mac, Windows10 で 迷走する1開発を進めていく備忘録5

【kintone カスタマイズ Tips】JavaScriptによる少数計算で生じる誤差

前記事では JavaScriptについて、割と好意的に書いている。だが、この際はっきり言うと、JavaScript にはいくつか罠がある。今回、記事にとりあげる少数計算(少数点以下の数値を含む計算)もそのひとつだ。

1. 突如現れる誤差の衝撃

それは前触れもなくやってくる。そう、少数を含む計算を行う際に。

let result = 0.1 * 0.1;
console.log(result);  //0.010000000000000002

なん・・・だと・・・。0.01が正解ではないのか?0.000000000000000002はどこから来た?と思うだろう。

なぜ、このような結果になるかというと、それはJavaScriptで扱う数値がIEEE754で規定されている浮動少数であることに起因する。更になぜ浮動少数かと掘り下げると、コンピューター内で数値は最終的にバイナリ形式で、1と0の並び(2進数)で表現されることにより密接に起因する。例えば、0.1 のように10進数では綺麗に表現できる数値でも、2進数で表すと0.00011001100… のように小数点第2位から0011が循環して永遠に終わることのない無限少数となる。これを決められたデータ型に格納するために有効桁数以下を丸めるべく2進法では0捨1入するわけで、その丸めた結果誤差が生じるのだ。(丸め誤差、と呼ばれる。)

2. どうすれば回避できるのか

よく取り沙汰されるのが、少数を整数にして計算し、再度少数に戻す方法。しかしながら、これは少数を整数にする際に少数計算が発生するため、結局誤差が生まれかねない。

そこで、一番シンプルで有効な回避策は、①いったん数値を文字列化し、文字列操作でドット(.)を排除して整数とする。②整数同士で計算を行ったうえで、元のドットの位置をもとに10^Nで割って元の少数へ戻す、という手順だと考える。うむ、これなら少数計算は発生しないので、誤差も生じない。

let strA = '0.1';
let strB = '0.1';
let dotposiA = (strA.length-1)-strA.indexOf('.'); //ドットの位置からstr1の少数点以下桁数を取得
let dotposiB = (strB.length-1)-strB.indexOf('.'); //ドットの位置からstr2の少数点以下桁数を取得
let preresult = parseInt(strA.replace('.','')) * parseInt(strA.replace('.',''));  //1
let N = dotposiA + dotposiB;
let result = preresult / Math.pow(10, N); //0.01 

期待する結果が得られ、なかなか良さげ。

そのほか、ライブラリを使う方法もある。有名どころでは、BigDecimal.js と decimal.js の2つがあるが、試しに decimal.js の方を使ってみた。

<script type="text/javascript" src="decimal.js"></script>
<script>
let a = 0.1;
let b = 0.1;
let dec = new Decimal(a);
console.log(dec.times(b).toNumber());  //0.01
</script>

これもよりシンプルでいい感じ。

* * *

このように JavaScript は、いくつか落し穴的な要素があるので、今後も機会を見て紹介していきたい。(他によく取り沙汰されるものとしては「日付の罠」がある。これは近日記事にしたいと思う。)

俺: 小林康典(KOBACHAN)

▼プロフィール畳む

▶プロフィール見る

時はネットが産声をあげた前世紀末、東京大手町に本社がある元国営の通信事業会社に新卒入社し、以降およそ10年間勤務して、インターネット系の新規事業立ち上げに複数携わる。

その後、退職して、ITベンチャーのスタートアップ参画を皮切りに、複数のIT/Web企業でプロダクトマネージャーを務めた後、縁あって現在の会員制ホテル&医療系事業会社へjoin。

元来、エンジニアばかりの環境で過ごしてきたが、ここは一般の非IT系事業会社でIT関連は全て外注。内製中心のアジャイル開発を企てるも、実際に技術がわかり手も動かせるIT担当者の存在はほぼ皆無で、参加直後から周囲の理解が得られず孤立無援の大ピンチ。

幾たびの紆余曲折を経て、技術やデザインに素養がある仲間を一人一人見つけアジャイル開発の世界に勧誘しては、知識・ノウハウを提供して地道に自律的な成長を促し、小規模ながらなんとか内製開発できるチームの形を整える。

現在、業務改善系ITプロダクトの企画およびシステム開発、ビッグデータ分析やAIビジネス転化への試行錯誤など、マルチに行い奮闘中。
(最近は、サイボウズ社のSaasサービス「キントーン」関連の開発多め。)

E-mail: contact@kobachan.biz

カテゴリー
月別アーカイブ
  • 2020 (1)
  • 2019 (2)
  • 2018 (5)
  • 2017 (6)