喫茶XRAYトップページ

[スレッド全体
]

[8086] マスター お疲れ様です返信 削除
2014/10/10 (金) 11:03:51 taki
▼ Mr.XRAYさん
 
> 確実に誤差のない計算を希望するのであれば,BCD 演算
> ということになります.また,Currency 型 (固定小数点形式) を使用すれば,
> 小数点 4 桁までは正確な演算が可能です.


マスター お疲れ様です。

え〜っと、通常の実数の演算は2進数で行われるので誤差が出るのですね。

例えば、a := 10; としても、実際には 9.9999999…がセットされているかも…ですね。
32Bitであろうと64BitであろうとDouble型であろうとExtended型であろうと
小数点以下の.999…の桁数が増えるだけということでしょうか。

でも、FloatToStrは「9.999…」と文字列にされると困るので、こそっと有効桁数で
丸め処理をして、「10」と表示しているのですね。なるほど。

それと、学校では四捨五入は4は切り捨てて、5は切り上げるとならったのですが、
銀行で使われている四捨五入は実は五捨五入で結果が常に偶数?になるように
なっているのですね。

例えば小数点1位で丸める場合、2.35→2.4、2.45→2.4、2.55→2.6、2.65→2.6
こうすると、増える方に丸め処理と減る方に丸める処理が同じ確率で行われ
全体としての誤差が減るのですね。
この事を知っていないと2進数の演算誤差と混ざって???となるのですね。

間違いがあったら突っ込んでください。m(_ _)m

昔使っていたIBMのマシンの演算はBCDだったようです。ファイルの数字が0〜9で
表現されてました。

そういえば、Z-80の命令に10進補正命令というのがあったのを思い出しました。


[8087] Re:マスター お疲れ様です返信 削除
2014/10/10 (金) 11:21:36 taki
> え〜っと、通常の実数の演算は2進数で行われるので誤差が出るのですね。
>
> 例えば、a := 10; としても、実際には 9.9999999…がセットされているかも…ですね。


やっちまった。

10は2進数1010で表現できてしまう。
正確には浮動小数点に変換する時に誤差がでるのか?

http://www.picfun.com/mathlib02.html

10は例としては不適当でした。スミマセン


[8088] いろいろテストしても意味がない?返信 削除
2014/10/10 (金) 14:06:11 Mr.XRAY
▼ takiさん

> でも、FloatToStrは「9.999…」と文字列にされると困るので、こそっと有効桁数で
> 丸め処理をして、「10」と表示しているのですね。なるほど。


おそらくそういうことではないかと思います.
ところが,質問された方のコードでは SimpleRoundTo で 2 桁にしてしまって
いますから,その時点で 15 桁で丸めるという「親切?」な仕様が意味なくなって
いるわけです.

素直に,FloatToStrF 関数, FloatToText 関数 や FloatToDecimal 関数等を利用
すればいいのですが,いい題材だと思って,思いつくまま書いてしまいました.
結果,まとまりのない書き込みになってしまいました(汗)

「敵?」のスキルや知識を知ることは難しいです.ハイ.
今回のような現象が起きると,過去の例では,いろいろ数値を変えたりして
テストする人が多いのですが,それは数値計算における演算誤差発生の様子を
調べているだけです.

私のように,素直に「コンピュータでの計算だからそんなもんだ」と
割り切ってしまうといいのですが...


[8089] Re:いろいろテストしても意味がない?返信 削除
2014/10/10 (金) 16:00:39 Mr.XRAY
> > でも、FloatToStrは「9.999…」と文字列にされると困るので、こそっと有効桁数で
> > 丸め処理をして、「10」と表示しているのですね。なるほど。
>
> おそらくそういうことではないかと思います.


これが曲者だったわけです.
計算結果を FloatToStr で文字列にしたら,数学的な計算結果と一致した.
しかし,本当は,15 桁目で丸めた結果なんですが.
そこで,何故同じ FloatToStr 関数を使用しているのに,小数点の以下の桁数を
指定したら誤差がでてしまうのか?
といったことではないでしょうか.多分.


[8090] Re2:いろいろテストしても意味がない?返信 削除
2014/10/10 (金) 17:30:48 taki
▼ Mr.XRAYさん

> 小数点の以下の桁数を
> 指定したら誤差がでてしまうのか?
> といったことではないでしょうか.多分.


10進数の179.935が2進数で近似されているわけだから、
その値は179.9349999999995〜179.9350000000004の間にある?
この条件なら15桁目で丸め処理をすると179.935になる。

関数で小数点以下の桁数を指定して丸め処理をしても、
179.94は179.9399999999995〜179.9400000000004の間にある?

う〜ん、私にはわかりません。(+_+)


[8094] Re3:いろいろテストしても意味がない?返信 削除
2014/10/11 (土) 19:14:18 Mr.XRAY
>その値は179.9349999999995〜179.9350000000004の間にある?

あ〜,こういうことを書かれると手抜きした私の立場が. (^^;
立場を取り戻すために,こんなことやってみました.ヘヘヘッ
ほとんど意味ありませんが.

小数点 16 桁目を調べるために 16 乗しています.
16 桁目も 9 になっています.あとちょっとだったようです
思ったのですが,15 桁で丸めるというのは,内部処理でも精度 16 桁が限界
だからなのかも知れません.


//-----------------------------------------------------------------------------
//  (1)と(2)の計算式は,数学的には等しく,179.935となる
//-----------------------------------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
  A, B, C, D, E, F : Extended;
  IntE : Int64;
  IntF : Int64;
begin
  Memo1.Lines.Clear;
  Memo1.Font.Name := 'MS ゴシック';
  Memo1.Font.Size := 10;

  A := 389.7;
  B := 94.4;
  c := 30;
  D := 0.35;
  E := (A + B + C) * D;        //(1)
  F := A * D + B * D + C * D;  //(2)

  //Int64は16乗が限界?
  IntE := Trunc(E * Math.Power(10, 16));
  IntF := Trunc(F * Math.Power(10, 16));

  Memo1.Lines.Add(IntToStr(intE));
  Memo1.Lines.Add(IntToStr(intF));
end;


[▼次のスレッド]
INCM/CMT
Cyclamen v3.82