浮点,是一个足以防止被零除的相等比较

Floating Point, is an equality comparison enough to prevent division by zero?

本文关键字:比较 一个 浮点      更新时间:2023-10-16
// value will always be in the range of [0.0 - maximum]
float obtainRatio(float value, float maximum){
    if(maximum != 0.f){
        return value / maximum;  
    }else{
        return 0.f;
    }
}

maximum的取值范围可以是任何数,也可以是负数。value的范围也可以是任何东西,尽管只有当输入在[0.0 - maximum]范围内时,该函数才需要"有意义"。输出应始终在[0.0 - 1.0]

的范围内。

我想知道两个问题,关于这个:

  • 这个相等比较是否足以确保函数永远不会被零除?
  • 如果最大值是一个退化值(非常小或非常大),是否有机会函数将返回[0.0 - 1.0]之外的结果(假设值在正确的范围内)?

这是一个迟来的回答,澄清了与这个问题有关的一些概念:

返回value/maximum

在浮点数中,除零不是像整数除零那样的致命错误。由于您知道value位于0.0maximum之间,因此唯一可能发生的除零是0.0 / 0.0,它被定义为生成NaN。对于函数obtainRatio来说,浮点值NaN是一个完全可以接受的值,并且实际上是一个比0.0更好的异常值,因为您建议的版本正在返回。

对浮点数的迷信只是迷信

在浮点数之间没有关于<=的近似定义。a略高于b时,a <= bnot有时求值为真。如果ab是两个有限的float变量,则a表示的有理数小于或等于b表示的有理数时,a <= b的值为true。唯一的小故障实际上不是故障,而是对上述规则的严格解释:+0.0 <= -0.0求值为真,因为"+0.0表示的理性"answers"-0.0表示的理性"都是0。

同样地,在浮点数之间没有关于==的近似:float的两个有限变量ab使a == b为真,当且仅当a表示的有理数与b表示的有理数相同。

if (f != 0.0)条件中,f的值不能是0的表示,因此被f除法不能是被0除法。该部门仍有可能人满为患。在value / maximum的特殊情况下,不可能发生溢出,因为您的函数需要0 ≤ value ≤ maximum。并且我们也不需要去怀疑前提条件中的是指有理数之间的关系还是指浮点数之间的关系,因为两者本质上是相同的。

这说

C99允许浮点表达式的额外精度,这在过去被编译器制造商错误地解释为使浮点行为不稳定的许可证(以至于程序if (m != 0.) { if (m == 0.) printf("oh"); }在某些情况下可能会打印"oh")。

实际上,提供IEEE 754浮点数并将FLT_EVAL_METHOD定义为非负值的C99编译器在测试后不能改变m的值。变量m在最后一次赋值时被设置为可表示为float的值,该值要么表示0,要么不表示0。只有操作和常量可以具有超精度(参见C99标准,5.2.4.2.2:8)。

在GCC的情况下,最近的版本对-fexcess-precision=standard做了正确的处理,由-std=c99暗示。

进一步阅读

  • David Monniaux几年前对C语言中浮点的悲惨状态的描述(第一版于2007年发布)。David的报告并没有试图解释C99标准,而是用真实的例子描述了C语言中浮点计算的现实情况。由于编译器的标准遵从性得到了改进,并且由于SSE2指令集使整个问题变得没有意义,情况已经得到了很大的改善。

  • Joseph S. Myers在2008年邮件列表中的帖子,描述了当时GCC中浮动的情况(坏),他如何解释标准(好)以及他如何在GCC中实现他的解释(好)。

在有限范围的情况下,应该可以。一般来说,先检查零可以防止除零,但如果除数接近零并且被除数很大,仍然有可能发生溢出,但在这种情况下,如果除数很小,被除数就会很小(两者都可以接近零而不会导致溢出)。