pep*_*er0 10 floating-point 64-bit portability ieee-754
我想知道我是否可以假设在相同的64位浮点数上的相同操作在任何现代PC和大多数常见编程语言中给出完全相同的结果?(C++,Java,C#等).我们可以假设,我们正在对数字进行操作,结果也是一个数字(没有NaN,INF等等).
我知道使用浮点数(IEEE 854-1987和IEEE 754-2008)有两种非常类似的计算标准.但是我不知道它在实践中是怎么回事.
小智 8
实现64位浮点的现代处理器通常实现接近IEEE 754-1985标准的东西,最近被754-2008标准取代.
754标准规定了从某些基本操作中得到的结果,特别是加法,减法,乘法,除法,平方根和否定.在大多数情况下,精确指定数值结果:结果必须是在舍入模式指定的方向上最接近精确数学结果的可表示数字(最接近,朝向无穷大,朝向零或朝向负无穷大).在"到最近"模式中,标准还指定了如何打破关系.
因此,不涉及溢出等异常条件的操作将在符合标准的不同处理器上获得相同的结果.
但是,有几个问题会影响在不同处理器上获得相同的结果.其中之一是编译器通常可以以各种方式自由地实现浮点运算序列.例如,如果在C中写入"a = b c + d",其中所有变量都声明为double,则编译器可以在双精度算术或具有更大范围或精度的内容中计算"b c".例如,如果处理器具有能够保持扩展精度浮点数的寄存器并且使用扩展精度执行算法不会比使用双精度算术执行任何CPU时间,则编译器可能使用扩展生成代码-精确.在这样的处理器上,您可能无法获得与在其他处理器上相同的结果.即使编译器定期执行此操作,在某些情况下也可能不会因为寄存器在复杂序列期间已满,因此它会将中间结果临时存储在内存中.当它这样做时,它可能只写64位双精度而不是扩展精度数.因此,包含浮点运算的例程可能会给出不同的结果,因为它是使用不同的代码编译的,可能在一个地方内联,并且编译器需要寄存器来处理其他内容.
一些处理器具有计算乘法和加法的指令,因此可以在没有中间舍入的情况下计算 "b c + d"并且获得比首先计算b c然后添加d 的处理器更准确的结果.
您的编译器可能有开关来控制这样的行为.
有些地方754-1985标准不需要独特的结果.例如,当确定是否发生了下溢(结果太小而无法准确表示)时,该标准允许实现在将有效数(分数位)舍入到目标精度之前或之后进行确定.因此,一些实现将告诉您在其他实现不会发生下溢时.
处理器的一个共同特征是具有"几乎IEEE 754"模式,通过替换零而不是返回标准所需的非常小的数量,消除了处理下溢的难度.当然,在这种模式下执行时,与在更兼容模式下执行时相比,您将得到不同的数字.出于性能原因,非兼容模式可能是编译器和/或操作系统默认设置的模式.
注意,IEEE 754实现通常不仅由硬件提供,而是由硬件和软件的组合提供.处理器可以完成大部分工作,但依靠软件来处理某些异常,设置某些模式等等.
当你超越基本的算术运算到诸如正弦和余弦之类的东西时,你非常依赖于你使用的库.超越函数通常使用精心设计的近似值计算.这些实现由各种工程师独立开发,并且彼此获得不同的结果.在一个系统上,sin函数可以在ULP(精度最小的单位)内为小参数(小于pi左右)提供准确的结果,但对于大参数则更大的错误.在另一个系统中,sin函数可以在几个ULP内为所有参数提供准确的结果.没有当前的数学库可以为所有输入生成正确的舍入结果.有一个项目,crlibm(正确的Rounded Libm),已经为这个目标做了一些很好的工作,他们已经为数学库的重要部分开发了实现正确舍入并具有良好性能的实现,但不是所有的数学库然而.
总之,如果您有一组可管理的计算,了解您的编译器实现,并且非常小心,您可以在不同的处理器上依赖相同的结果.否则,获得完全相同的结果并不是您可以信赖的.
如果你的意思得到完全相同的结果,那么答案就是否定.
在某些情况下,您甚至可能会在同一台计算机上对调试(非优化)构建与发布构建(优化)获得不同的结果,因此甚至不要假设结果在不同的计算机上总是相同的.
(例如,在具有Intel处理器的计算机上,如果优化器为寄存器中的中间结果保留变量,则可能会发生这种情况,存储在未优化构建的内存中.由于Intel FPU寄存器为80位,双变量为64 bit,中间结果将以更高的精度存储在优化的构建中,从而在以后的结果中产生不同的值.).
但是,在实践中,您可能经常得到相同的结果,但您不应该依赖它.
| 归档时间: |
|
| 查看次数: |
711 次 |
| 最近记录: |