对于一个浮点数a:当a为有限值时,a * 0.0 == 0.0是否总是成立?

10

我一直认为以下测试在somefloat是有限值(没有INF,没有NAN)时总是会成功的:

assert(somefloat*0.0==0.0);

“乘以0的优化”中指出,double a=0.0double a=-0.0严格来说并不是一回事。

因此我想知道这是否会在某些平台上引起问题,例如上述测试的结果是否取决于a是正数还是负数。


1
C++标准要求+0.0-0.0具有相同的行为。您引用的线程中提出的另一种观点是错误的,至少对于C和C++而言。 - James Kanze
1
这不是浮点运算,而是双精度运算。 - Lundin
3
@James:标准规定正零和负零比较相等,并不意味着它们在所有情况下的行为都相同。atan2函数是否允许(但不需要)返回一个关于 atan2(ZERO,ZERO)atan2(NEGATIVE_ZERO,NEGATIVE_ZERO) 值不同的结果?因此,另一个问题中这种优化的有效性并不只是两个可能结果是否相等的问题。但我认为你所写的是正确的,因为据我所知,在C和C++中,表达式-0.0不会评估为负零。 - Steve Jessop
@Lundin:你说得对,标题有误,不应该提到float。我已经更改了它。我不想指定somefloat是float还是double。 - Martin
1
@James:这不是UB,当两个参数都为零时,“它是一个域错误”。域错误意味着返回一个实现定义的值(可能)。因此,对于尊重负零并将该值定义为取决于输入符号的实现,它们不能仅仅因为优化而随意丢弃零的符号,因为后来可能会在atan2中使用它。当然,这个问题中的断言是另一回事。 - Steve Jessop
显示剩余12条评论
3个回答

9
如果你的实现使用IEEE 754算术(大多数实现都是这样),那么正零和负零将比较相等。由于对于有限的a,左侧表达式只能为正零或负零,所以断言将始终为真。
如果它使用其他类型的算术,那么只有实现者,并且希望特定于实现的文档可以告诉你。可以认为(请参见评论)标准的措辞意味着在任何情况下它们必须相等,并且肯定没有理智的实现会做出其他选择。

@James 你有标准的参考资料吗? - Andreas Brinck
@Mike Seymour 根据不同的解释,5.3.1/7 可能就是它了。"一元减运算符的操作数必须具有算术或枚举类型,其结果是其操作数的否定*。零的否定是零。 - Andreas Brinck
只是出于兴趣:这也适用于不同的浮点类型,例如 float a = 0.0; double b = -a * 0.0; assert(a == b); 吗? - Martin
2
除非你正在使用非常特殊的数学,否则基本定义运算符中已经有了这个答案:“如果指定的关系为真,则每个运算符应产生“true”,如果为假,则产生“false”。” -0.0 等于 0.0,所以 -0.0 == 0.0 必须返回 true。也可以从 C 标准的§5.2.4.2.2/1中推断出这一点。但我同意它可能不够清晰。 - James Kanze
1
@Martin 我也这么认为,但你可能需要查阅 C 标准的 §5.2.4.2.2/1 来加以证明(这部分内容包含于 C++ 标准的 §18.2.2 中——不是你首先查找此类信息的确切位置)。 - James Kanze
显示剩余2条评论

3

-0.0和0.0在双精度比较规则下相等。

对于非有限值(+-Inf,Nan),某些浮点数*0.0!=0.0。


1
NaN 作为有限值有点奇怪。OP 询问有限值。 - nhahtdh
刚刚优化了代码。在我的特定场景中,不会出现NAN。 - Martin
“对于非有限值(+-Inf,Nan),somefloat*0.0!= 0.0”是什么意思?这看起来有点混乱,还是只是格式问题? - Martin
@Martin:我预计的意思是,“如果somefloat是+无穷大、-无穷大或NaN,则somefloat*0. != 0.的结果为true。” - Eric Postpischil

1

只要somefloat不是无穷大或NaN,您的assert就永远不会失败。在不支持无穷大或NaN的系统上,编译器可以简单地将其优化掉。


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