Ers*_*hin 1 delphi floating-point delphi-xe2
我写了一个代码,但它产生了错误的结果!
Var
a,d:double;
c:currency;
b:integer;
begin
b:=10;
c:=20.1;
a:=30.1;
d:=0;
d:=a-b-c;
Memo1.Lines.Add('a => '+FloatToStr(a));
Memo1.Lines.Add('b => '+FloatToStr(b));
Memo1.Lines.Add('c => '+FloatToStr(c));
Memo1.Lines.Add('d => '+FloatToStr(d))
end;
Run Code Online (Sandbox Code Playgroud)
结果:
a => 30.1
b => 10
c => 20.1
d => 1.4210854715202E-15
Run Code Online (Sandbox Code Playgroud)
结果应该是零!这个编译器类型转换错误吗?
有没有办法?!!
好吧,首先要说的是你在这里玩火.你在混合Integer,Double并Currency在同一声明中.坦率地说,那种不圣洁的混合物在寻找麻烦.
最重要的是,如果您还不知道,您应该知道并非所有值都可以表示.以下是源值:
a是类型Double,价值30.1.该值在二进制浮点中不能完全表示.该最接近的Double值是30.10000000000000142108547152020037174224853515625.b是类型Integer,价值10.这里没有惊喜.c是类型Currency,价值20.1.这表示为64位整数,值为201000.这是一个定点十进制数据类型.该表示包括10000的隐式移位.接下来你的表达,a - b - c.它从左到右进行评估.
x86下的代码看起来像这样,带有我的注释:
// load b into the floating point unit, converting from 32 bit integer fild dword ptr [$00423ef0] // subtract b from a, as floating point fsubr qword ptr [$00423ed8] // multiply by 10000 to convert to currency fmul dword ptr [$0041c5e0] // load c into the floating point unit, converting from 64 bit integer fild qword ptr [$00423ee8] // subtract c from (b - a) fsubp st(1) // divide by 10000, that is convert the result to a floating point value fdiv dword ptr [$0041c5e0] // store this floating point value into d fstp qword ptr [$00423ee0]
我们存储的值d不等于零.基本上是因为(a - b)*10000 <> 20100.现在,您可能会对此感到惊讶,(a - b)*10000 <> 20100但这a不是30.1我们在上面第一个要点中看到的事实的自然结果.
我认为这个故事的寓意不是在同一个表达式中混合使用二进制和十进制操作数.或者至少如果你需要这样做,请清楚准确地说明你是如何做到的.例如.
因此,如果您完全执行计算,Currency那么您将得到您期望的答案.那是因为Currency是十进制表示,可以精确地存储所有这些值和所有中间值.
| 归档时间: |
|
| 查看次数: |
62 次 |
| 最近记录: |