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

Ann*_*inn 13 c c++ floating-point

// 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

范围maximum可以是任何东西,包括负数.范围value也可以是任何东西,但是当输入在范围内时,该功能仅需要"有意义" [0.0 - maximum].输出应始终在范围内[0.0 - 1.0]

我有两个问题,我想知道,有这个:

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

Pas*_*uoq 14

这是一个迟到的答案,澄清了与该问题相关的一些概念:

只返回值/最大值

在浮点数中,除零不是像整数除零那样的致命错误.既然你知道value0.0和之间maximum,那么可以发生的唯一除零0.0 / 0.0就是定义为生成NaN.浮点值NaN是函数obtainRatio返回的完全可接受的值,实际上是一个更好的异常返回值0.0,因为你提出的版本正在返回.

关于浮点的迷信只是迷信

关于<=浮动之间的定义没有任何近似.a <= b没有时,有时会评估为真a只是一个小小的以上b.如果a并且b是两个有限float变量,则a <= b当所表示的理性a小于或等于所表示的理性时,恰好评估为真b.人们可能认识到的唯一一点小故障实际上并不是一个小故障,而是对上述规则的严格解释:+0.0 <= -0.0评价为真,因为"理性代表+0.0"和"理性代表-0.0"都是0.

类似地,浮点数之间没有任何近似值==:两个有限float变量a,当且仅当表示的理性和表示的理性相同时才b变为a == b真.ab

在一个if (f != 0.0)条件内,值f不能表示为零,因此除法f不能除以零.分裂仍然可能溢出.在特定情况下value / maximum,因为您的功能需要,不会有溢出0 ? value ? maximum.而且我们不需要怀疑 ?在前提条件下是指理性之间的关系还是浮动之间的关系,因为这两者基本上是相同的.

这说

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

实际上,提供IEEE 754浮点并定义FLT_EVAL_METHOD为非负值的C99编译器不能更改m测试后的值.变量m设置为上次分配时可表示为float的值,该值表示为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浮动的情况(糟糕),他如何解释标准(好)以及他如何在GCC(GOOD)中实施他的解释.