C ++ / C#与float和double的区别

时间:2010-08-26 23:41:30

标签: c# c++ floating-point double

我们正在将C ++数学库转换为C#。该库混合使用浮点数和双精度数(有时在它们之间进行转换)我们正在尝试做同样的事情,以便在C#中获得与C ++中完全相同的结果,但事实证明这是非常困难的,如果不是不可能的话

我认为问题是以下一个或多个问题,但我不是专家:

  1. 将浮动转换为double和double转换为浮动导致不可预测的结果,并在C ++和C#中以不同方式完成

  2. C ++和C#处理浮点精度的方式不同,它们无法模仿彼此

  3. .NET中有一个设置可以让它像C ++一样运行,但我找不到它(都是32位)

  4. 有人可以向我解释可能存在的问题,也许可以将我与微软的一些权威文档联系起来,我可以用它来帮助解释这种情况以及产生差异的原因吗?

    修改
    我们使用的是VC6和.NET4.0

    由于NDA的原因,我不能举出计算的例子,但我可以为差异显示一些数字......他们自己可能很无用:

     8.085004000000000 (C#) vs. 
     8.084980000000000 (C++)    
    
     8.848165000000000 (C#) vs. 
     8.848170000000000 (C++)   
    
     0.015263214111328 (C#) vs. 
     0.015263900756836 (C++)  
    

    应该指出的是,这些数字包括复杂的问题。这些是计算结果。

1 个答案:

答案 0 :(得分:10)

C ++允许程序为临时结果保留比子表达式所暗示的更高的精度。可能发生的一件事是中间表达式(或它们的未指定子集)被计算为扩展的80位浮点数。

另一方面,如果这适用于C#,我会感到惊讶,但即使它是,C#编译器也不必选择相同的表达式子集来计算为80位延长花车。编辑:见下面Eric的评论。

More details

相同的中间精度问题的另一个实例是当编译器使用fmadd指令进行乘法,然后在源代码中添加(如果目标体系结构具有它 - 例如,PowerPC)。 fmadd指令准确计算其中间结果,而正常添加则会对中间结果进行舍入。

为了防止C ++编译器这样做,您应该只需要使用volatile变量为中间结果编写浮点计算作为三地址代码。如果此转换更改了C ++程序的结果,则意味着上述问题正在发挥作用。但后来你改变了C ++方面的结果。在没有读取生成的程序集的情况下,可能无法在C#中获得完全相同的旧C ++结果。

如果它有点旧,你的C ++编译器也可以优化浮点计算,就好像它们不相关时一样。你无能为力。这是不正确的。三地址代码转换将再次阻止编译器应用它,但同样没有简单的方法让C#编译器重现旧的C ++结果。