5

Borland Pascal7とDelphi2007の両方に、数値、長さ、精度を取り、次のような文字列に変換するプロシージャSTRがあります。

str(9.234:5:1, s); // -> s = '  9.2'

丸めがあいまいでない場合はすべて問題ありませんが、そうでない場合(0.5->上または下?)には問題があります。BPの浮動小数点データ型に依存しているようですが、Delphi2007では明らかに一貫しています。 :

BP:

var
  e: extended;
  d: double;
begin
  d := 2.15;
  e := 2.15;
  str(d:5:1, s); { -> s = '  2.1' }
  str(e:5:1, s); { -> s = '  2.2' }
  { but: }
  d := 2.25
  e := 2.25
  str(d:5:1, s); { -> s = '  2.3' }
  str(e:5:1, s); { -> s = '  2.3' }

ダブルスがどのように丸められるかについての規則を見つけることができませんでしたが、明らかに拡張されたものは常に切り上げられます。

Delphi 2007は、データ型に関係なく常に切り上げられるようです。

BPでdouble値の丸めがどのように行われるかを知っている人はいますか?

doubleを使用するBorlandPascalコードをDelphi2007に移植している最中であり、出力を比較すると、STRプロシージャでの丸めの結果として不整合が発生するためです。これらは結果にとって実際には重要ではありませんが、重要な違いを見つけることは非常に困難です。

4

5 に答える 5

4

d=2.15とd=2.25の場合は異なります。

2.15はfloat形式で正確に表現できないため、特定のfloat形式でのfloat値のバイナリ表現を分析せずに、値がどのように丸められるかを言うことはできません。

2.25はfloat形式で正確に表され、丸め結果は予測可能でなければなりません。

浮動小数点形式で正確に表されるいくつかの値で丸めをテストしましたが、STRは常に正の値の場合は切り上げ、負の値の場合は切り下げます。STRは、「銀行の丸め」には従いません。例:

  d := 2.25;
//  d:= roundto(d, -1);  banker's rounding is 2.2
  str(d:5:1, s); { -> s = '  2.3' }

  d:= 2.75;
//  d:= roundto(d, -1);  banker's rounding is 2.8
  str(d:5:1, s); { -> s = '  2.8' }
于 2010-02-25T17:12:16.817 に答える
2

あなたが見ている問題は、10進数表記で正確に表現できる多くの数値は、2進数の循環小数(2進数?)としてしか表現できないことだと思います。したがって、2.15をdoubleで正確に表すことはできず、2.14999999999234(または何か)がバイナリ表現で取得できる最も近いものである可能性があります。

数値の最も近い2進表現は厳密に2.15未満であるため、Str関数は切り上げではなく切り捨てられます。

于 2010-02-25T15:39:13.930 に答える
1

浮動小数点の丸め誤差のように見えます。Delphiで生成されたアセンブリコードを見ると、両方の操作で_Str2Extが呼び出され、Extendedが文字列に変換されていることがわかります。したがって、それを行うには、Doubleを舞台裏でExtendedに変換する必要があります。

Project1.dpr.16: str(d:5:1, s); { -> s = '  2.1' }
0040E666 DD45E8           fld qword ptr [ebp-$18]
0040E669 83C4F4           add esp,-$0c
0040E66C DB3C24           fstp tbyte ptr [esp]
0040E66F 9B               wait 

そして、DoubleからExtendedへの変換のどこかで、精度が少し失われ、最初にExtendedと同じ数値を宣言した場合(私たちが読んだように)とはわずかに異なる数値になってしまいます。これは浮動小数点変換ではかなり一般的です。あなたがそれについて何かできることがあるかどうかわからない。

于 2010-02-25T15:52:18.247 に答える
0

これを調べたところ、0.000001を追加するとdoubleの正しい結果が得られることがわかりました。

于 2010-02-25T15:45:36.220 に答える
0

ここには2つの側面があることに注意してください。

まず、10進数のリテラル値は、2進数の浮動小数点数に丸められる可能性があります。これは、アセンブリコードに入力された数が、書き留めた数とわずかに異なる可能性があることを意味します。最も近いマシン番号がわずかに少ない場合は、切り上げが必要な値がSTRによって切り捨てられているように見えることがあります。

次に、結果の2進浮動小数点数は、FPUステータスワードで構成された丸めを使用して丸められます。これは、外部ライブラリによって変更されていないことを願っています。

于 2010-02-25T16:06:59.920 に答える