我们正在将C ++数学库转换为C#。该库混合使用浮点数和双精度数(有时在它们之间进行转换)我们正在尝试做同样的事情,以便在C#中获得与C ++中完全相同的结果,但事实证明这是非常困难的,如果不是不可能的话
我认为问题是以下一个或多个问题,但我不是专家:
将浮动转换为double和double转换为浮动导致不可预测的结果,并在C ++和C#中以不同方式完成
C ++和C#处理浮点精度的方式不同,它们无法模仿彼此
.NET中有一个设置可以让它像C ++一样运行,但我找不到它(都是32位)
有人可以向我解释可能存在的问题,也许可以将我与微软的一些权威文档联系起来,我可以用它来帮助解释这种情况以及产生差异的原因吗?
修改
我们使用的是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++)
应该指出的是,这些数字包括复杂的问题。这些是计算结果。
答案 0 :(得分:10)
C ++允许程序为临时结果保留比子表达式所暗示的更高的精度。可能发生的一件事是中间表达式(或它们的未指定子集)被计算为扩展的80位浮点数。
另一方面,如果这适用于C#,我会感到惊讶,但即使它是,C#编译器也不必选择相同的表达式子集来计算为80位延长花车。编辑:见下面Eric的评论。
相同的中间精度问题的另一个实例是当编译器使用fmadd
指令进行乘法,然后在源代码中添加(如果目标体系结构具有它 - 例如,PowerPC)。 fmadd
指令准确计算其中间结果,而正常添加则会对中间结果进行舍入。
为了防止C ++编译器这样做,您应该只需要使用volatile变量为中间结果编写浮点计算作为三地址代码。如果此转换更改了C ++程序的结果,则意味着上述问题正在发挥作用。但后来你改变了C ++方面的结果。在没有读取生成的程序集的情况下,可能无法在C#中获得完全相同的旧C ++结果。
如果它有点旧,你的C ++编译器也可以优化浮点计算,就好像它们不相关时一样。你无能为力。这是不正确的。三地址代码转换将再次阻止编译器应用它,但同样没有简单的方法让C#编译器重现旧的C ++结果。