【问题标题】:Can bad stuff happen when dividing 1/a very small float?除以 1/非常小的浮点数时会发生坏事吗?
【发布时间】:2010-06-02 02:05:54
【问题描述】:

如果我想检查正浮点数 A 是否小于另一个正浮点数 B 的平方反比(在 C99 中),如果 B 非常小,会出现问题吗?

我可以想象像这样检查它

if(A<1/(B*B))

但是如果 B 足够小,这可能会导致无穷大吗?如果发生这种情况,代码是否仍能在所有情况下正常工作?

以类似的方式,我可能会这样做

if(1/A>B*B)

...这可能会稍微好一些,因为如果 B 很小,B*B 可能为零(这是真的吗?)

最后,一个我无法想象是错误的解决方案是

if(sqrt(1/A)>B)

我认为这不会导致除法为零,但如果 A 接近于零,仍然可能会出现问题。

所以基本上,我的问题是:

  • 如果 X 大于零(但很小),那么 1/X 能否成为无穷大?
  • 如果 X 大于零,X*X 是否可以为零?
  • 与无穷大的比较会按照我的预期进行吗?

编辑:对于那些想知道的人,我最终做了

if(B*A*B<1) 

我是按这个顺序做的,因为它在视觉上是明确的,哪个乘法首先发生。

【问题讨论】:

  • 你说的有多小?你可能对0.0000000000000000000000003 有一些问题,可以这么说,但如果不知道你的输入浮点数的精度是多少,就很难回答这个问题。
  • AFAIK,你可能会得到一个小除数的算术溢出,但不是零除数错误。
  • if ( A*B*B &lt; 1 ) 怎么样?
  • B 输入来自用户图形滑块或文本输入,因此我应该能够优雅地处理任何大小,即使某些淘气的人输入 0.0000000000000000000000003。 A 输入来自大于十左右数字的浮点减法计算,所以我也希望它可能非常小,但小得离谱,因为它应该失去准确性。
  • Nikolai,我想你可能有解决办法。这绝不会导致任何溢出或除以零,这正是我正在寻找的答案。您应该将其发布为答案!

标签: c floating-point division divide-by-zero


【解决方案1】:

如果您想处理AB 的整个可能值范围,那么您需要小心一点,但这真的不是太复杂。

使用a*b*b &lt; 1.的建议不错;如果b 太小以至于a*b*b 下溢为零,那么a 必然小于1./(b*b)。相反,如果b 太大以至于a*b*b 溢出到无穷大,那么条件将(正确地)不被满足。 (Potatoswatter 在另一篇文章的评论中正确指出,如果你写 b*b*a,这可以正常工作,因为 b*b 可能会溢出到无穷大,即使如果a 恰好是非正规的,则条件应该为真。但是,在 C 中,乘法从左到右关联,因此如果您编写它a*b*b 并且您的平台遵循合理的数字模型,则这不是问题。 )

因为您先验知道ab 都是正数,所以a*b*b 无法生成NaN,因此您不必担心这种情况.上溢和下溢是唯一可能的不当行为,我们已经对它们进行了解释。如果您需要支持ab 可能为零或无穷大的情况,那么您需要更加小心。

回答您的直接问题:(答案假定为 IEEE-754 算法)

如果 X 大于零(但很小),那么 1/X 是否可以是无穷大?

是的!如果 x 是一个小的正非正规值,则1/x 可能会溢出并产生无穷大。例如,在默认舍入模式下的双精度,1 / 0x1.0p-1024 会溢出。

如果 X 大于零,X*X 是否可以为零?

是的!在默认舍入模式下的双精度下,所有小于0x1.0p-538(即C99 hex 格式中的2**-578)左右的x 值都有这个属性。

与无穷大的比较会按照我的预期进行吗?

是的!这是 IEEE-754 的最佳特性之一。

【讨论】:

  • 谢谢!我会更多地研究非规范值(不是因为我担心,只是感兴趣)
【解决方案2】:

好的,作为答案转发。

尝试使用算术等价比较,例如if ( A*B*B &lt; 1. )。但是,您可能会遇到非常大的数字的麻烦。

请仔细查看 IEEE 754 以了解您的特殊情况。

【讨论】:

  • 其实,只要他不需要支持零或无穷大作为ab 的值(听起来他没有),那么就不存在极端情况的问题;它们都正确脱落。
【解决方案3】:

您想避免除法,所以诀窍是修改等式。您可以将第一个等式的两边乘以 (b*b) 得到:

b*b*a < 1.0

这不会有任何分裂,所以应该没问题。

【讨论】:

  • 不错!测量两次,切割一次。提问:如果这段代码不是不言自明的,那么添加必要的 cmets 以使其清楚。
  • 除法有点慢,但没有毒性。这里的问题是 bb 很容易溢出。 ab 其中 a>1 和 b
  • @Potatoswatter:假设 IEEE-754 浮点,溢出是无害的,无论如何这都会给出正确的答案。下溢也是如此。
  • @stephen: 不完全……如果a 是非正规的,那么b*b 可能会溢出到无穷大并抛出结果。
  • @Potatoswatter: 啊,没发现这个是b*b*a 而不是正确的a*b*b(它确实工作正常,因为乘法关联left-to - 就在 C 中)。
【解决方案4】:

部门本身并没有那么糟糕。但是,由于非规范化数字,标准 IEEE 754 FP 类型允许的负指数范围比正指数范围更大。例如,float 范围从 1.4×10-45 到 3.4×10-38,所以不能取 2×10-44.

因此,正如 Jeremy 建议的那样,首先将 A 乘以 B,其中一个具有正指数,另一个具有负指数,以避免溢出。

这就是为什么A*B*B&lt;1 是正确答案的原因。

【讨论】:

    猜你喜欢
    • 2012-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-02
    • 2022-10-02
    相关资源
    最近更新 更多