これは、Delphi での回帰のように見えます。
Delphi 2010 では出力が「奇妙」ですが、XE2 では出力がないため、バグは存在しません。テストする XE は手元にありませんが、XE も「奇妙な」出力をすることを確認してくれた @Sertac に感謝します。古いバージョンの Delphi も問題ないため、これは D2009 頃の回帰であることに注意してください。
2010年に生成されたコードは次のとおりです。
Project106.dpr.10: if C < 1.32 then
004050D6 DB2D18514000 fld tbyte ptr [$00405118]
004050DC DF2D789B4000 fild qword ptr [$00409b78]
004050E2 DED9 fcompp
004050E4 9B wait
004050E5 DFE0 fstsw ax
004050E7 9E sahf
004050E8 7319 jnb $00405103
Project106.dpr.12: WriteLn('strange');
リテラル 1.32 は、値 13200 を持つ 10 バイトの浮動小数点値として格納されます。これは正確に表現可能なバイナリ浮動小数点値です。10 バイト浮動小数点数として格納される 13200 のビット パターンは次のとおりです。
00 00 00 00 00 00 40 CE 0C 40
ただし、リテラルの $00405118 に格納されているビット パターンは異なり、 よりわずかに大きくなって13200
います。値は次のとおりです。
01 00 00 00 00 00 40 CE 0C 40
C < 1.32
そして、それが評価される理由を説明していTrue
ます。
XE2 で生成されるコードは次のとおりです。
Project106.dpr.10: if C < 1.32 then
004060E6 DF2DA0AB4000 fild qword ptr [$0040aba0]
004060EC D81D28614000 fcomp dword ptr [$00406128]
004060F2 9B wait
004060F3 DFE0 fstsw ax
004060F5 9E sahf
004060F6 7319 jnb $00406111
Project106.dpr.12: WriteLn('strange');
ここで、リテラルが 4 バイトの float で保持されていることに注意してください。これは、 と比較してみるとわかりdword ptr [$00406128]
ます。に格納されている単精度浮動小数点数の内容を見ると、次の$00406128
ことがわかります。
00 40 4E 46
そして、それは 4 バイトの float として表される正確に 13200 です。
私の推測では、2010 年のコンパイラは、に直面したときに次のことを行い1.32
ます。
- 1.32 を最も近い正確に表現可能な 10 バイト浮動小数に変換します。
- その値に 10000 を掛けます。
- 結果の 10 バイト float を に格納し
$00405118
ます。
1.32 は正確に表現できないため、最終的な 10 バイトの float は正確に 13200 ではないことがわかります。おそらく、コンパイラがこれらのリテラルを 4 バイトの float に格納することから 10 バイトの float に格納するように切り替えたときに、回帰が発生しました。
基本的な問題は、データ型に対する Delphi のサポートがCurrency
、まったく欠陥のある設計に基づいていることです。2 進浮動小数点演算を使用して 10 進固定小数点データ型を実装すると、問題が発生するだけです。設計を修正する唯一の正気の方法は、固定小数点整数演算を使用するようにコンパイラを完全に再設計することです。新しい 64 ビット コンパイラが 32 ビット コンパイラと同じ設計を使用していることに注意してください。
正直に言うと、Delphi コンパイラがCurrency
リテラルで浮動小数点演算を行うのを止めたいと思います。それは完全な地雷原です。頭の中で 10,000 シフトを次のように行います。
function ShiftedInt64ToCurrency(Value: Int64): Currency;
begin
PInt64(@Result)^ := Value;
end;
そして、呼び出しコードは次のようになります。
C := 1.32;
if C < ShiftedInt64ToCurrency(13200) then
Writeln ('strange');
コンパイラがそれを台無しにする方法はありません!
ふん!