简单计算,c#和delphi中的结果不同

时间:2009-04-29 15:55:43

标签: c# delphi

问题是,为什么这些代码片段会产生不同的结果?

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.有人可以给我一个详细的解释吗?

非常感谢!

8 个答案:

答案 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。

事实并非如此。如果使用小数,答案是正确的。但正如他所说,范围不同。