2

次のコードでは、最後の 2 つの呼び出しでCeil予期しない結果が生じています。その理由についてコメントしていただけますか?

さらに、エラー (または偏差) がランダムな場合、期待値を取得できますか?

Ceil(Calculated_Var_Value) = 7いつCalculated_Var_Value = 7.0000000000

どうもありがとう!

    procedure TForm2.FormCreate(Sender: TObject);
    var
      A, B, C: Extended;
      Val: Extended;
    begin
      ShowMessage(FloatToStr((1.8 - 2.5) / -0.1));
      ShowMessage(FloatToStrF((1.8 - 2.5) / -0.1, ffFixed, 20, 20));
      ShowMessage(FloatToStr(Ceil((1.8 - 2.5) / -0.1)));


      Val := (1.8 - 2.5) / -0.1;
      ShowMessage(FloatToStr(Val));
      ShowMessage(FloatToStrF(Val, ffFixed, 20, 20));
      ShowMessage(FloatToStr(Ceil(Val)));


      Val := (1.8 - 2.5) / -0.1;
      ShowMessage(FloatToStr(Val * 100 / 100));
      ShowMessage(FloatToStrF(Val * 100 / 100, ffFixed, 20, 20));
      ShowMessage(FloatToStr(Ceil(Val * 100 / 100)));


      A := 1.8; B := 2.5; C := -0.1;
      Val := (A - B) / C;
      ShowMessage(FloatToStr(Val));
      ShowMessage(FloatToStrF(Val, ffFixed, 20, 20));
      ShowMessage(FloatToStr(Ceil(Val)));


      A := 1.8; B := 2.5; C := -0.1;
      Val := (A - B) / C;
      ShowMessage(FloatToStr(Val * 100 / 100));
      ShowMessage(FloatToStrF(Val * 100 / 100, ffFixed, 20, 20));
      ShowMessage(FloatToStr(Ceil(Val * 100 / 100)));
    end;
4

2 に答える 2

4

これは、浮動小数点演算に固有の不正確さによるものです。2つの値は、バイナリ浮動小数点で正確に表現できませ1.8-0.1。したがって、これらの数値は、最も近い表現可能な値で概算されます。そして、それはあなたの方程式が正確に評価されないことは非常にもっともらしいことを意味します7

次に、2つの式について考えます。

Val1 := (1.8 - 2.5) / -0.1;
Val2 := (A - B) / C;

これら2つの違いはVal1、コンパイル時にVal2評価され、実行時に評価されることです。さて、定数式(1.8 - 2.5) / -0.1がどのように評価されるかはコンパイラー次第です。私の知る限り、それがどのように評価されるかは文書化されていません。

ただし、コンパイラが実行時に使用されるものとは異なる評価方法を使用して定数式を評価することは明らかです。このプログラムは次のことを示しています。

{$APPTYPE CONSOLE}

uses
  SysUtils, Math;

var
  A, B, C: Extended;
  Val1, Val2: Extended;
begin
  Val1 := (1.8 - 2.5) / -0.1;
  Writeln(Ceil(Val1));

  A := 1.8; B := 2.5; C := -0.1;
  Val2 := (A - B) / C;
  Writeln(Ceil(Val2));

  Writeln(BoolToStr(Val1=7.0, True));
  Writeln(BoolToStr(Val2=7.0, True));
  Writeln(BoolToStr(Val1<Val2, True));

  Readln;
end.

出力:

7
8
真
誤り
真

したがって、これはVal1Val2が異なる値を持っていることを示しており、それVal2は厳密に。よりも大きいです7

あなたが抱えている根本的な問題は、代表的に浮動小数点値の問題です。バイナリ表現を使用するを使用しているためExtended、10進数の入力値は正確に表現できません。ここで正確な算術演算が必要な場合は、10進表現を使用する必要があります。

この質問の変形に答えるときはいつものように、私はあなたに主題に関する本質的な読み物を参照します:すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと

于 2013-02-04T00:02:50.710 に答える
2

これは典型的な丸め誤差です。次の行を出力に追加すると、次のように表示されます。

ShowMessage(FloatToStr(Val-7));
于 2013-02-04T00:02:03.540 に答える