技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

JavaScript:小数点以下の丸め誤差に対応する

JavaScriptでは数値リテラルがNumber型(浮動小数点型)として扱われるため、何も考えずに小数点以下の計算を行うと誤差が発生します。
この問題への対処法は他の記事でも紹介していますが、大きく分けて以下の2つが存在します。
1.数値項目の単位を変えた上で整数型で計算を行う
2.任意精度型で計算を行う
 
以下では、JavaScriptの場合の具体的な対処法について紹介します。
 
--------------
 
1.数値項目の単位を変えた上で整数型で計算を行う
JavaScriptには、BigInt型という整数型が用意されています。
数値リテラルの末尾に"n"をつけることで、BigInt型として扱われます。
 
整数型であるため、計算結果で小数が発生する場合は全て切り捨てが行われます。
この性質を利用して、切り上げや四捨五入を行うこともできます。
以下は、切り捨て・切り上げ・四捨五入を行うサンプルコードです。
 
【サンプルコード】
console.log("■1桁目で切り捨て");
console.log("・(109n) / 10n * 10n");
console.log( (109n) / 10n * 10n);
console.log("・(110n) / 10n * 10n");
console.log( (110n) / 10n * 10n);
console.log("■1桁目で切り上げ");
console.log("・(100n + 9n) / 10n * 10n");
console.log( (100n + 9n) / 10n * 10n);
console.log("・(101n + 9n) / 10n * 10n");
console.log( (101n + 9n) / 10n * 10n);
console.log("■1桁目で四捨五入");
console.log("・(104n + 5n) / 10n * 10n");
console.log( (104n + 5n) / 10n * 10n);
console.log("・(105n + 5n) / 10n * 10n");
console.log( (105n + 5n) / 10n * 10n);
console.log("■おまけ:下2桁を小数とみなして表示");
console.log("・110nを表示");
let bigint = 110n;
let integer = bigint.toString().slice(0,-2)
let point = ".";
let decimal = bigint.toString().slice(-2);
console.log(integer + point + decimal);
 
【実行結果】
■1桁目で切り捨て
・(109n) / 10n * 10n
100n
・(110n) / 10n * 10n
110n
■1桁目で切り上げ
・(100n + 9n) / 10n * 10n
100n
・(101n + 9n) / 10n * 10n
110n
■1桁目で四捨五入
・(104n + 5n) / 10n * 10n
100n
・(105n + 5n) / 10n * 10n
110n
■おまけ:下2桁を小数とみなして表示
・110nを表示
1.10
 
---------------------
 
2.任意精度型で計算を行う
JavaScriptでは標準で任意精度型は用意されていませんが、外部ライブラリを取り込むことで任意精度型を利用することができます。
今回は、BigNumberを紹介します。
 
BigNumberは、リンク先のGitHubで「Code」→「Download ZIP」を選択することでダウンロードできます。
ダウンロードされたファイルの中には、「bignumber.js」が存在するので、これを実行環境の任意の場所に配置します。
 
取り込み方や使用方法は、README.mdに書かれています。
使用方法については、英語ということもあり不親切に感じるかもしれませんが、Webで検索すれば日本語のわかりやすい説明も出てきます。
 
以下では、Node.jsで小数点計算を試すサンプルコードです。
(「bignumber.js」は実行するスクリプトと同一階層に配置する前提です)
 
【サンプルコード】
// BigNumberの取り込み
const BigNumber = require('./bignumber.js');

// 計算
console.log("■標準機能で0.3-0.2");
let ng = 0.3 - 0.2;
console.log(ng.toString());

console.log("■BigNumberで0.3-0.2");
let ok = new BigNumber(0.3).minus(0.2);
console.log(ok.toString());
 
【実行結果】
■標準機能で0.3-0.2
0.09999999999999998
■BigNumberで0.3-0.2
0.1