誤差がない計算を行うには

◆PROCESSING 逆引きリファレンス

 カテゴリー:演算処理

誤差がない計算を行うには

【概要】

プログラムでは、小数点を扱うことが良くあります。例えば円の面積を求めたり、商品単価を計算する場合などでしょうか。

プログラムで小数点を扱うには、float や double などの浮動小数点型の変数を使うのが一般的ですが、これらの型は時として計算誤差を引き起こします。

例えば上記のプログラムでは、float 型の変数 fval と double 型の変数 dval を用意して、ぞれぞれ 1.0 から 0.9 を引いています。

机上の計算では(言うまでもなく)答えは 1.0  – 0.9  = 0.1 となりますが、プログラム上の計算では 0.1 にはなりません。

このように計算誤差を起こしてほしくない場合は、float や double 型を使うのではなく、JavaのBigDecimalクラスを使って計算を行います。

ただしBigDecimalクラスを使った計算は、Mathクラスの命令やPROCESSINGの標準命令を使うのに比べて、かなり遅いです。

ですので、なんでもかんでもBigDecimalを使えばOKという事ではなく、ケース・バイ・ケースだという事に注意してください。

PROCESSINGの標準命令で四捨五入や切り捨て、切り上げを行うには「四捨五入、切り捨て、切り上げ」記事を参照してください。

 

【詳細】

変数作成

変数を作成するBigDecimal dec = new BigDecimal( String val  );
BigDecimal bdc = BigDecimal.valueOf( long val );

bdc : BigDecimal値
val  : 変換元の値

BigDecimal クラスのインスタンス変数を作成する代表的な例です。

val には String 型や long 型以外にも double 型の値を与えることが可能ですが、オススメしません。

上記例を御覧ください。

double 型の値( 0.1 )を与えた場合、せっかく BigDecimal クラスを利用しているのに誤差が生じています。これは double 型そのものが 0.1 という値を正確に保持できないためです。

小数点を正確に扱いたいなら、BigDecimal のインスタンス変数を作成する時にもdouble型は使わずに、(3)のように String 型で指定しましょう。

 

四則演算

四則演算BigDecimal bdc = bdc1.add( BigDecimal bdc2 ); //足し算
BigDecimal bdc = bdc1.subtract( BigDecimal bdc2 ); //引き算
BigDecimal bdc = bdc1.multiply( BigDecimal bdc2 ); //掛け算
BigDecimal bdc = bdc1.divide( BigDecimal bdc2 ); //割り算

bdc : BigDecimal値
bdc1 : 計算する値1
bdc2 : 計算する値2

それぞれ四則演算を行うメソッドです。

注意は割り算です。BigDecimal クラスで割り切れない計算(1 ÷ 0.3 など)を行うと ArthmeticException 例外が発生します。

この例外を発生させない為には、割り算を行う際に計算の「丸め」を指定する必要があります。

 

割り算の丸め指定BigDecimal bdc = bdc1.divide( BigDecimal bdc2, RoundingMode mode );
BigDecimal bdc = bdc1.divide( BigDecimal bdc2, int scale, RoundingMode mode);

bdc : BigDecimal値
bdc1 : 計算する値1
bdc2 : 計算する値2
scale : 小数点以下の値の数。0なら小数点以下なし、1なら小数点以下1桁
mode : 丸め指定

丸め指定には以下が利用可能です。
ただし RoundingMode.UNNECESSARY を指定すると、scale 以上の桁数をもつ小数点値を与えた場合、ArthmeticException 例外となります。

丸め指示 動作
1 RoundingMode.HALF_UP 四捨五入 +1.66 => 1.7
2 RoundingMode.CEILING 正の方向へ大きくなるように切り上げ +1.66 => 1.7
3 RoundingMode.DOWN 切り捨て -1.66 => -1.6
4 RoundingMode.FLOOR 負の方向へ小さくなるように切り捨て -1.66 => -1.7
5 RoundingMode.HALF_DOWN 五捨六入 +1.55 => 1.5、
+1.56 => 1.6
6 RoundingMode.HALF_EVEN 末尾が偶数のほうに四捨五入する(銀行丸め) +1.65 => 1.6、
+1.55 => 1.6
7 RoundingMode.UP 0 から離れるように切り上げ -1.64 => -1.7、
+1.64 => 1.7
8 RoundingMode.UNNECESSARY 丸めない -1.64 => -1.64

 

丸め指定

精度指定BigDecimal bdc = BigDecimal val.setScale( int scale, RoundingMode mode );

bdc : BigDecimal値
val: 丸める値
scale : 小数点以下の値の数。0なら小数点以下なし、1なら小数点以下1桁
mode : 丸め指定

丸め指定は、BigDecimal値に対して直接指定することも可能です。

なお本記事の執筆にあたっては、以下のサイト様を参考とさせて頂きました。ありがとうございます。

 

【関連記事】

 


サンプルプログラム

四則演算例:

シンプルな四則演算例です。割り算には注意してください。本例では割り切れる値を利用していますが、割り切れない場合は例外が発生します。

<出力サンプル>

 

割り算の丸め指定例:

各種丸め指定を使って、循環小数が発生する割り算を行わせています。

<出力サンプル>

 

単体で丸め指定する例:

BigDecimal値に丸め指定を行っています。

<出力サンプル>

 


PROCESSING逆引きリファレンス一覧 へ戻る

本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。