Doubleの計算について


とも  2006-03-01 17:23:07  No: 20284  IP: 192.*.*.*

ダブルの計算が上手くいかず悩んでいます。
a_Dが2053.22だと以下の変換ではa_iが2053219に変換されてしまいます。
その他の数字でどの数字がこういった現象になるかは、いろいろ試した結果
確認されていません。

    a_D := a_D*power(10,3);
    a_i := Trunc(a_D);

なぜこのような数字になるのでしょうか?
宜しくお願いします。

編集 削除
はむれっと  2006-03-01 18:28:48  No: 20285  IP: 192.*.*.*

>なぜこのような数字になるのでしょうか?
最後の桁を「切り捨て」すると、1減ることがあるのは浮動小数点演算の宿命かな。
1000倍した時に
2053220.00000000.....
ではなくて
2053219.99999999.....
になっているんでしょうね。
これがいやなら、Double型ではなく、誤差を出来るだけ小さくした Currency型を使うべきでしょう。

編集 削除
とも  2006-03-02 08:55:48  No: 20286  IP: 192.*.*.*

はむれっとさん回答ありがとうございます。
そうなんですね〜。

ただ一部
  a_i := Trunc(a_D);

  a_i := StrtoInt(FloattoStr(a_D));
に変更したらうまくいきました。
Truncだと何かやってるんですかね?
ただこういった現象が、変更後によって全部の数字に対して回避できるのか不安です。
どのように対処しようか悩んでいます。。

編集 削除
えーと  2006-03-02 11:00:59  No: 20287  IP: 192.*.*.*

それは、Delphi というより、すべての実数計算には誤差がつきものだ、という
当たり前のことを理解してないからです。回避する、とかの問題ではありません。

数値を限られたビット数で表す限り、実数計算の誤差は本質的なことです。

編集 削除
ふむ  2006-03-02 11:10:57  No: 20288  IP: 192.*.*.*

var a_D: Double; ではなく
var a_D: Externded; とするとa_iは2053220となるので
function Trunc(X: Extended): Int64; で Extendedに変換される時に誤差が現れる様ですね。
Truncで切り捨てをするなら Trunc(a_D+0.5); の様に四捨五入しても場合によっては良いと思います

編集 削除
ふむ  2006-03-02 11:12:53  No: 20289  IP: 192.*.*.*

var a_D: Extended; 
書きミス

編集 削除
それはね…  2006-03-02 11:26:06  No: 20290  IP: 192.*.*.*

>  a_i := StrtoInt(FloattoStr(a_D));
>に変更したらうまくいきました。
>Truncだと何かやってるんですかね?

実数を文字列に変換するルーチンでは四捨五入で数値を丸めているので、Trunc の返す値と異なる場合があるということ。
四捨五入でいいのなら、Round関数を使いましょ。

編集 削除
あの手この手、ダレの手?  2006-03-02 11:32:27  No: 20291  IP: 192.*.*.*

Trunc の返す値と Roundの返す値が異なる場合、
どっちを選ぶかユーザーに問い合わせてみる?
それとも、それをDebugログに記録しておく?

編集 削除
Ru  2006-03-09 15:30:08  No: 20292  IP: 192.*.*.*

ちょうど調べてる最中に気になるのみ付けたので書き込みます。

>四捨五入でいいなら,Round関数を使いましょ。

Round関数では四捨五入にはなりません。あくまで丸めるだけの関数の模様です。

ttp://www2.big.or.jp/~osamu/Delphi/tips.cgi?index=0073.txt

編集 削除