x87 FPU值得注意的是使用内部80位精度模式,这通常会导致编译器和机器出现意外和不可重现的结果。 In my search对.NET再现的浮点运算,我发现.NET(微软和Mono)的两个主要实施方式中发射SSE指令,而不是64位模式下的x87
SSE(2)严格使用32位寄存器用于32位浮点数,严格使用64位寄存器用于64位浮点数。通过设置appropriate control word可以选择将非正规数刷新为零。
因此,SSE似乎不会受到x87的精度相关问题的影响,并且唯一的变量是可以控制的非正规行为。
不考虑超越函数(SSE本身不像x87那样提供),是否使用SSE保证了机器和编译器之间可重现的结果?例如,编译器优化会转化为不同的结果吗?我发现了一些相互矛盾的观点:
如果您有SSE2,请使用它并从此过上幸福的生活。 SSE2支持 32b和64b操作以及中间结果都是 操作数的大小。 - Yossi Kreinin ,http://www.yosefk.com/blog/consistency-how-to-defeat-the-purpose-of-ieee-floating-point.html
...
SSE2指令(...)完全符合IEEE754-1985标准 允许更好的再现性(由于静态舍入 精度)和其他平台的便携性。 Muller et aliis , Handbook of Floating-Point Arithmetic - p.107
但是:
此外,您不能将SSE或SSE2用于浮点,因为它也是如此 指定不确定。 - John Watte http://www.gamedev.net/topic/499435-floating-point-determinism/#entry4259411
答案 0 :(得分:11)
SSE完全指定*。 Muller是浮点运算专家;在游戏论坛上你会信任谁,他还是某个人?
(*)对于非IEEE-754操作,例如rsqrtss,实际上有一些例外,其中英特尔从未完全指定行为,但这不影响IEEE-754基本操作,更重要的是它们的行为可以'实际上在这一点上有所改变,因为它会破坏太多东西的二进制兼容性,所以它们和指定的一样好。
答案 1 :(得分:4)
正如斯蒂芬所说,由给定的SSE汇编代码产生的结果将是可重复的;你输入相同的代码相同的输入,你得到相同的输出。 (也就是说,约翰沃特的引用是错误的。)
你在那里扔了“编译器”这个词。这完全是一个不同的球赛。许多编译器在保留浮点代码的正确性方面仍然非常糟糕。 (The ATLAS errata page提到clang“无法为某些操作生成正确的代码。”)如果在代码中使用特殊函数,那么在某种程度上,您也可以使用实现数学库的任何人。