我写了一段代码,但结果不正确!
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;
结果:
a => 30.1
b => 10
c => 20.1
d => 1.4210854715202E-15
结果应该是零! 此编译器类型转换错误?
有没有办法?!!
答案 0 :(得分:5)
嗯,首先要说的是你在这里玩火。您在同一声明中混合了Integer
,Double
和Currency
。坦率地说,那种不圣洁的混合物在寻找麻烦。
最重要的是,如果您还不知道,您应该知道并非所有值都可以表示。以下是源值:
a
是Double
类型,值30.1
。该值在二进制浮点中不能完全表示。 closest Double
value为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
的精确表示这一事实的自然结果,正如我们在上面的第一个要点中看到的那样。 / p>
我认为这个故事的寓意不是在同一个表达式中混淆二进制和十进制操作数。或者至少如果你需要这样做,请清楚准确地说明你是如何做到的。例如。
因此,如果您完全在Currency
中执行计算,那么您将得到您期望的答案。那是因为Currency
是十进制表示,可以精确地存储所有这些值和所有中间值。
答案 1 :(得分:0)
Var
a,d:double;
c:double;
b:double;
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;
结果:
a => 30.1
b => 10
c => 20.1
d => 0
改善相同类型变量的问题!!!
&#34;双&#34;如果我们继续使用错误,则在分配不同类型(货币)的值时键入。