誤差が出るということは

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

上はJavaに限らずほとんどの言語で注意すべきもので、言語を覚える前にまず知るべき基礎的な知識。電子計算機概論ってやつだな。

お金を扱う場所では必須の知識。入社1年目でも知るべきもっとも大事なもの。消費税計算するときにa = b * 1.05なんてかいたら終わり。


固定小数点前提のCOBOLとかみたいなの標準でほしいよね。


んでやっと本題。

演算誤差が出るってことはイコールによる判定ができないんだよね。

float a = 0.1f;
float b = 1-0.1f*9;

while(a != b){
}

これ、Javaだと無限ループするよね。0.1はIEEE 754であらわせない数字なんで。

だからJUnitでもassertEqualsはどれくらいの誤差を出してよいのかという判定方法のため、引数が2つではない。昔は引数2つのメソッドがあってなんでこんなの実装したんだとかいわれてたはず。今は非推奨メソッドになってます。


C言語だと浮動小数点フォーマットや演算方法が規定されてないから(IEEE 754とは限らない。今はされてるのかな?)実装依存

とまぁ、制御関係で浮動小数点がきたらかなり神経質になる必要がある。演算の結果が違うのあh出力して気がつくが、流れが変わるのはかなりわかりにくい。


ちなみに上は以下のようにかくとよい。

float a = 0.1f;
float b = 1-0.1f*9;

while(Math.abs(a - b) <= 0.01f){
}

毎回こうするのはだるいのでequalsのユーティリティクラス作るはず。ShinGL4でも一応用意した。


ちなみにBigDecimalも多桁長整数(BigInteger)+10進スケールの浮動小数点ではあるけど。



あとCPUで10進演算用意してないってのも大きいかな。FPUがCPUに取り込まれることになったとき、ほとんどの人はそう思ったはずだと思うけど。

最近は10bitで3桁あらわす効率がよいタイプがでてきてるけれども、まずは最も単純なBCD演算でも標準化されていればなぁ。今はCPUの命令直接触ることはほとんどないとはいえ・・・ということはあれか。「ABCD」という命令見てなんという適当なネーミング…とか勘違いする楽しさもないのか。

64bitで表せる数はとんでもないんだから64bitのレジスタ使って10進スケールの固定小数点演算命令があればお金の計算なら大概十分だと思うけどね。




デフォでBigDecimal使うGroovyはもっと評価されていいと思う。