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

Jas*_*son 7 c# c++ floating-point double

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

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

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

  2. C++和C#处理浮点精度的方式不同,它们不能相互模仿

  3. .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++)  
Run Code Online (Sandbox Code Playgroud)

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

Pas*_*uoq 10

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

另一方面,如果这适用于C#,我会感到惊讶,但即使这样做,C#编译器也不必选择相同的表达式子集来计算为80位扩展浮点数.编辑:请参阅Eric的评论如下.

更多细节

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

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

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

  • 关于你的第二段,我将你引用C#规范的第4.1.6节,它开始**浮点运算的执行精度可能高于操作的结果类型.例如,某些硬件体系结构支持"扩展"或"长双"浮点类型,其范围和精度比double类型更大,并使用此更高精度类型隐式执行所有浮点运算....**有关详细信息,请参阅规范. (2认同)