浮动值在发行版和调试版中的行为有所不同

时间:2020-03-06 14:48:24  来源:igfitidea点击:

在发布模式和调试模式下编译时,我的应用程序生成不同的浮点值。我发现的唯一原因是我保存了一个二进制跟踪日志,而发布版本中的一个与调试版本略有不同,看起来32位浮点值的底部两位大约相差1/2的情况。

我们会认为这种"差异"是一个错误,还是这种差异是预期的。这是编译器错误还是内部库错误。

例如:

LEFTPOS and SPACING are defined floating point values.
float def_x;
int xpos;

def_x = LEFTPOS + (xpos * (SPACING / 2));

问题与X360编译器有关。

解决方案

这不是错误。任何浮点更新都有一定的不精确性。在发布模式下,优化将更改操作的顺序,我们将获得略有不同的结果。不过,差异应该很小。如果很大,我们可能还会遇到其他问题。

发行模式可能具有不同的FP策略集。有不同的浮点算术模式,具体取决于我们所需的优化级别。例如,MSVC具有严格,快速和精确的模式。

我帮助一位同事找到了一个导致版本与调试版本不同的编译器开关,这引起了他的不同。

看一下/ fp(指定浮点行为)。

不是错误。这种差异是可以预期的。

例如,某些平台的浮点寄存器使用的位比存储在内存中的位更多,因此与存储到内存和从内存中重新加载相比,在寄存器中保留一个值可能会产生略有不同的结果。

这种差异很可能是由编译器优化引起的,通常是在发布模式下完成,而不是在调试模式下完成。例如,编译器可能会对某些操作进行重新排序以加快执行速度,这可能会导致浮点结果略有差异。

因此,我想说这很可能不是错误。如果我们真的对此感到担心,请尝试在"调试"模式下打开优化。

我知道在PC上,浮点寄存器为80位宽。因此,如果完全在FPU内完成计算,我们将获得80位精度的好处。另一方面,如果将中间结果移入普通寄存器然后又移回,则会被截断为32位,从而得到不同的结果。

现在考虑,发布版本将进行优化,以将中间结果保留在FPU寄存器中,而调试版本可能会天真地在存储器和寄存器之间来回复制中间结果,因此行为有所不同。

我不知道这是否也发生在X360上。

像其他提到的那样,浮点寄存器比浮点寄存器具有更高的精度,因此最终结果的精度取决于寄存器分配。

如果需要一致的结果,可以使变量易变,这将导致速度变慢,精度降低但结果一致。

除了其他浮点模式以外,其他人还指出,可以打开SSE或者类似的矢量优化以进行发布。将浮点运算从标准寄存器转换为向量寄存器会影响结果的低位,因为向量寄存器通常比标准浮点寄存器更窄(位更少)。

如果设置了允许编译器重新排序浮点运算的编译器开关,则-e.g。 / fp:fast-那么显然这不是错误。

如果我们未设置任何此类开关,那么这就是一个错误-C和C ++标准不允许编译器在未经我们许可的情况下对操作进行重新排序。