将浮点数与零进行比较

4
我想检查一个IEEE754 32位数字是否恰好具有0.0f的值(它偶尔会被设置为此值)。由于数据将经常从传感器更新,累积误差将为零。我的处理器没有硬件FPU,因此操作是在相当快的软件库中完成的。但是,像加、减和比较这样的操作仍需要数百个周期。
所以我想知道我的编译器为什么会这样做:
240:                 if(p_viewer->roll != 0.0f)
 03FBC  B81160     mul.uu w2,#0,w2
 03FBE  900A2E     mov.w [w14+20],w4
 03FC0  900064     mov.w [w4+12],w0
 03FC2  9000F4     mov.w [w4+14],w1
 03FC4  07E91F     rcall __nesf2
 03FC6  E00000     cp0.w w0
 03FC8  320054     bra z, 0x004072

__nesf2 显然是比较两个浮点数。为什么它不直接对0.0f进行整数形式的比较,即0x00000000?它为什么不这样做或者说这只是一次未能实现的优化机会?

我的编译器是MPLAB C30,是GCC v3.23的一个版本。

4个回答

7

因为根据IEEE-754标准的要求,-0.0f也等于0.0f

如果这是一个重大的性能问题,您可以使用两个整数表示来替换调用,分别是-0(0x80000000)和+0。 (或者更好的方法是,屏蔽符号位并与0.0f进行比较)。


1
我在想为什么编译器没有这样做,这可能只需要最多10个周期,而__nesf2函数需要约100个周期。 - Thomas O
1
除了信号NaN的问题,这只是一个被遗漏的优化。提交一个错误报告。 - Stephen Canon
考虑到编译器的年龄(gcc 3.2.3?),很可能存在许多未优化的问题,而且没有人有兴趣去修复它。 - David Thornley
@David:如果在gcc主线中还没有修复,如果有人提交了错误报告,最终会有人来解决它。未报告的错过优化永远不会得到修复。 - Stephen Canon
@David:这是GCC v3.23的一个分支。 - Thomas O

1
如果这是一个IEEE浮点实现,它必须考虑到信号NaN。
你可能不关心这个,但编译器并不知道。

是的,但这有什么关系吗?NaN 永远不会等于非 NaN。 - Thomas O
@Thomas O:一个信号NaN可能会导致陷阱,而整数比较则不会。然而,软件FP实现几乎从不支持信号NaN,因此这是不太可能的。 - Stephen Canon
@Stephen Canon,我不认为我的有信号NaN。你可以除以零,但只会得到NaN。没有其他事情发生。 - Thomas O
@Thomas O:被零除并不会创建一个信号NaN;在拥有它们的实现中,获取信号NaN的唯一方法是从文件中读取或在内存中创建一个。 - Stephen Canon
出于好奇,您可以尝试一下您最喜欢的x86编译器是否对信号NaNs做了任何特殊处理。它可能不会这样做。 - gnasher729

1

这是一个被错过的优化机会。0.f是一个特殊情况,因为它需要与-0.f和0.f进行比较。但是,将其作为整数进行比较仍然会更快。

为什么没有进行优化?我敢打赌这是一个集成问题。像这样的东西通常会被忽略。负责组装平台SDK的人选择编译器(gcc)、软件浮点库,并尽力将它们最好地粘合在一起。这在一般情况下可以正常工作,而且很少有改进的动力,因为软件浮点通常非常慢。最糟糕的部分不是比较,而是其他所有的东西。

简单来说,如果你使用软件浮点,那么如果你需要性能,就没有使用它们的意义了。对于这个问题,请使用定点数。


0.f 是一个特殊情况吗?只要您知道其中一个不是 NaN(例如,如果其中一个是字面常量),则可以按位比较任何浮点数值。实际上,零是最糟糕的,因为您必须检查正零和负零。对于任何其他值,单个比较就足够了。 - R.. GitHub STOP HELPING ICE

0

要检查是否等于0.0f,您不需要使用IEEE相关内容,例如:

int isFloatNull(float f)
{
  static float i;
  return !memcmp(&i,&f,sizeof i);
}

@kotlinski 如果更快,那就更好,无论它是否替代函数调用都无所谓。 - Thomas O
当然,对于负零它会给出错误的结果,因此这是毫无用处的。 - gnasher729

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接