📑

JavaScriptで小数点付きの計算をしよう

2022/06/18に公開

はじめに

記事の修正や追加等はコメントまたはGitHubの編集リクエストをお待ちしております。

また、この記事の内容は私が個人的に開発しているモジュールのコードを抜き出した物です。

https://github.com/riya-amemiya/UMT

特別な処理がいる理由

JavaScriptは計算の際暗黙的に2進数で計算しています。
例えば0.1を2進数にすると0.000110011001100…となります。

> 0.1 * 0.1
0.010000000000000002

これは小数点がなくなるように 10のn乗 すると解決します
(n=小数点以下の桁数)

小数点以下の桁数を求める

. 以下の桁数さえ分かればいいので split で切り出します。

const getDecimalLength = (value: number) => {
    let x = (value + '').split('.')[1];//splitで分割して小数点以下を取得
    if (typeof x !== 'undefined' && x.length > 0) {
        return x.length;
    }
    return 0;
};

実際に計算してみる

掛け算

import getDecimalLength from './getDecimalLength';

const multiplication = (x: number, y: number) => {
    const n = 10 ** (getDecimalLength(x) + getDecimalLength(y));
    x = +(x + '').replace('.', '');
    y = +(y + '').replace('.', '');
    return (x * y) / n;
};

足し算

import getDecimalLength from './getDecimalLength';
import max from './max';
import multiplication from './multiplication';

const addition = (x: number, y: number) => {
    const z = Math.pow(
        10,
        max([getDecimalLength(x), getDecimalLength(y)]),
    );
    return (multiplication(x, z) + multiplication(y, z)) / z;
};

割り算

import { getDecimalLength } from './getDecimalLength';
import { valueSwap } from './valueSwap';
export const division = ((
    x: number,
    y: number,
) => {
    const [decimalLengthX, decimalLengthY] = valueSwap(
        getDecimalLength(x),
        getDecimalLength(y),
    );
    const n =
        decimalLengthX == decimalLengthY
            ? 1
            : Math.pow(10, decimalLengthY - decimalLengthX);
    x = +(x + '').replace('.', '');
    y = +(y + '').replace('.', '');
    return x > y
            ? x / y / n
            : (x / y) * n
}

引き算は逆のことをやればいいので省略。

まとめ

覚えておいて損はないと思います。

いつの日か小数点がらみの誤作動に出逢ったら是非この記事へ。

宣伝

今回コードの説明はGitHub Copilotにやってもらいました。

詳しくはこちら

https://zenn.dev/riya_amemiya/articles/7a7cec9244e4b9

ブログやってます。

https://amemiya-riya-blog.oshaburikitchin.com/

Discussion