はじめに
背景と概要
- 要件
- JavaScriptを使用して小数n桁の四捨五入を行う
- 計算結果はExcelと合わせること
JavaScriptのMathオブジェクトでは小数n桁の指定ができません。
JavaScriptライブラリを使用できない事情があり、関数を作ることにしました。
この際、負数の計算で、JavaScriptとExcelの結果に差異が発生してしまいました。
この問題を解決するまでの知見を共有します。
前提バージョン
- ECMA Script 2015
問題点
まずは、こんなコーディングをしてみました。
数値と端数処理桁数を受け取り、四捨五入した結果を返す関数です。
function myRound(number, pricision) {
var _pow = Math.pow(10, pricision);
return Math.round(number * _pow) / _pow;
};
正の数値では期待どおり動作しましたが、負数の場合には以下のような計算結果となりました。
元の値 | JavaScript | Excel |
---|---|---|
-5.4 | -5 | -5 |
-5.5 | -5 | -6 |
-5.9 | -6 | -6 |
Excelの計算と異なってしまっており、要件を満たせません。
解決策と得られた知見
JavaScript(Math)とExcelでは、負数の四捨五入の仕様が異なりました。
MDN - Math.round()
すなわち0.5を丸める「向き」が、マイナス方向か、ゼロ方向かの違いです。
- Excelはマイナス方向に丸め処理するため、-5.5 → -6
- JavaScriptはゼロ方向に丸め処理するため、-5.5 → -5
という訳です。
コードを以下のように修正したところ、Excelと同じ計算結果となりました。
function myRound(number, pricision) {
var _sign = (number < 0) ? -1 : 1;
var _pow = Math.pow(10, pricision);
return Math.round((number * _sign) * _pow) / _pow * _sign;
};
負数の切り捨て・切り上げの場合も同じ原理で、JavaScriptとExcel関数では結果が異なります。
MDN - Math.floor()
MDN - Math.ceil()
なお、Javaの場合も、MathクラスとBigDecimalクラスでは負数の端数処理の向きが逆になります。
Javaの負の数の切り捨て・四捨五入にはご注意!
ということで、負数の端数処理については、「向き」に気をつけましょう!