「小数点の計算をやるからといってすぐにfloatやdoubleを使ってはいけない」へ

http://d.hatena.ne.jp/j5ik2o/20091024/1256369305

(桁数によってはintやlongを整数部と小数部に分けて演算する方法が考えられますがずばり面倒ですw←勘違いでしたw 多少演算速度が遅くともBigDecimalがよいですw)

System.out.println(1.00-9*.10);

これは0.1mの棒9本並べたときに1mにあとどれだけ届かないかという計算と同じですよね。小数点嫌いだからcmで表現したとすると

100.0-9*10.0

となります。各項は整数なので

100 - 9 * 10

とすることができます。結果は誤差なしで10cmが得られます。表示するときに望む単位への変換が必要にはなりますが、このように整数値に重みを考慮して扱うことで、ある桁数/精度での演算を高速に行なうことができます。

ただし演算の際のオーバーフローや重みの違う整数値を混ぜてしまったりしてもコンパイラーはチェックしてくれないと思うので注意が必要です。

このような数値表現を固定小数点数といいます。

なお、お金の計算にはBigDecimalという主張に異を唱えるものではありません。

上の説明だと9が9そのままだったりちょっとごまかしがあります。cで固定少数点演算っぽく書くと

#include

int
main(int argc, char *argv[])
{
int l;
int n;
int x;
int y;

int a,b;

l = 100; // 100cm = 1m
x = 10; // 10cm =0.1m
n = 900; // 900= 9 *100

// y = l - x * n

a = (x * n )/ 100;
a = -a;

b = l;
a = a + b;
printf( "a=%d means %f\n", a, a/100.0 );

}

のようになるでしょう。なんで掛け算のところで/100してるのと思うかもしれませんがこれは必要です。詳しくはりゅうさんの固定小数点数の演算 (-- 基礎から学ぶコンピュータ --第四十九号》)が参考になります。

なおもともと1という値を100で表現することは、整数を2進数で表したときの最下位ビット(LSB)の重みが0.01ということです。ただ実際に使われる場合はLSBが1/(2^n)の重みで使われることが多いです。その場合には当然0.1のような2進数で循環小数になる数は正確には表せません。