BigNumber.jsの丸め処理のタイミング


背景

TypeScriptの実装中、BigNumber.jsで丸め処理を行おうとしたが上手く作用しなかった。

↓コード例

// typescript

// 小数点5位以下を切り捨て
const roundDown4: typeof BigNumber = BigNumber.clone({
    ROUNDING_MODE: BigNumber.ROUND_DOWN,
    DECIMAL_PLACES: 4
});

const A: number = 100;
const B: number = 3;
const C: number = 20;

// A÷B×Cの結果を小数点5位以下を切り捨てしたい
// 期待値 = 100÷3×20 = 666.6666666~ ⇒ 666.6666

const result: BigNumber = roundDown4(A).div(B).times(C);

console.log(result.toString());
// 出力結果: 666.666
// 期待値と異なる


原因

BigNumber.jsの仕様

ROUNDING_MODEとDECIMAL_PLACESの設定に間違いはなかった。
しかし、ROUNDING_MODEとDECIMAL_PLACESの設定が適用されるのは
①roundDown4(X) と宣言したタイミング
②.div(Y) と割り算が行われたタイミング
である。
したがって、コード例では
A÷B×Cの結果を小数点5位以下で切り捨てしようとしているが、
実際の結果はA÷Bの結果を小数点5位以下で切り捨てた後に×Cが行われている。

対応内容

A÷B×C = A×C÷Bなので処理の順番を入れ替えた。

// × const result: BigNumber = roundDown4(A).div(B).times(C);
// ○ const result: BigNumber = roundDown4(A).times(C).div(B);

const result: BigNumber = roundDown4(A).times(C).div(B);
 
console.log(result.toString());
// 出力結果: 666.6666
// 期待の結果を得られた

今後への学び


除算は最後に付けよう!!!!!!

でないと除算のタイミングで丸め処理が行われる。