问题是,为什么这些代码片段会产生不同的结果?
private void InitializeOther()
{
double d1, d2, d3;
int i1;
d1 = 4.271343859532459e+18;
d2 = 4621333065.0;
i1 = 5;
d3 = (i1 * d1) - Utils.Sqr(d2);
MessageBox.Show(d3.ToString());
}
和
procedure TForm1.InitializeOther;
var d1, d2, d3 : Double;
i1 : Integer;
begin
d1:=4.271343859532459e+18;
d2:=4621333065.0;
i1:=5;
d3:=i1*d1-Sqr(d2);
ShowMessage(FloatToStr(d3));
end;
Delphi代码给了我816,而c#代码给了我0.使用计算器,我得到775.有人可以给我一个详细的解释吗?
非常感谢!
答案 0 :(得分:12)
Delphi将中间值存储为Extended(80位浮点类型)。此表达式为Extended:
i1*d1-Sqr(d2);
C#也是如此(我不知道)。额外的精确度可能会有所不同。
答案 1 :(得分:11)
请注意,您在此处处于Double数据类型精度的极限,这意味着此处的计算将不准确。
示例:
d1 = 4.271343859532459e+18
可以说是相同的:
d1 = 4271343859532459000
所以:
d1 * i1 = 21356719297662295000
实际上,.NET中的值更像是这样:
2.1356719297662296E+19
注意那里的四舍五入。因此,在这个级别,你没有得到正确的答案。
答案 2 :(得分:5)
这当然不是对这种确切情况的解释,但它有助于解释这个问题。
What Every Computer Scientist Should Know About Floating-Point Arithmetic
答案 3 :(得分:4)
C#double最多具有16位精度。以4.271343859532459e + 18乘以5将得到19位数字。您想要一个只有3位数的数字。 Double不能这样做。
在C#中,Decimal类型可以处理此示例 - 如果您知道使用123M格式初始化Decimal值。
Decimal d1, d2, d3;
int i1;
d1 = 4.271343859532459e+18M;
d2 = 4621333065.0M;
i1 = 5;
d3 = (i1 * d1) - (d2*d2);
MessageBox.Show(d3.ToString());
这给出775.00这是正确的答案。
答案 4 :(得分:3)
任何这样的计算都将导致具有典型浮点运算的戏剧。数字缩放的差异越大,准确度问题的可能性就越大。
http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems提供了一个很好的概述。
答案 5 :(得分:0)
我认为这是由精度有限引起的错误(最重要的是,因为使用双精度而不是整数)。分配后d1可能不一样。 d2 * d2肯定会与正确的值不同,因为它大于2 ^ 32。
由于5 * d1甚至大于2 ^ 64,即使使用64位整数也无济于事。您必须使用bignums或128位整数类才能获得正确的结果。
答案 6 :(得分:0)
基本上,正如其他人所指出的那样,双精度对于你想要的计算规模来说不够精确。 Delphi默认使用“扩展精度”,它在Double上增加了16位,以便进行更精确的计算。 .NET框架没有扩展精度数据类型。
不确定您的计算器使用的是什么类型,但它显然与Delphi和C#有所不同。
答案 7 :(得分:0)
正如其他人评论的那样,双精度对于计算来说并不够精确。 小数是一个很好的替代事件,尽管有人指出它会被舍入而不是。
在C#中,Decimal类型无法轻松处理此示例,因为4.271343859532459e + 18将四舍五入为4271343859532460000。
事实并非如此。如果使用小数,答案是正确的。但正如他所说,范围不同。