C 标准库提供了 round
, lround
, 和 llround
C99 中的函数族。但是,这些函数不符合 IEEE-754,因为它们没有实现 IEEE 规定的半对偶的“银行家四舍五入”。如果小数部分恰好为 0.5,则半对偶四舍五入要求将结果四舍五入到最接近的偶数。如 cppreference.com 中所述,C99 标准改为要求离零一半。
1-3) Computes the nearest integer value to arg (in floating-point format), rounding halfway cases away from zero, regardless of the current rounding mode.
在 C 中实现舍入的常用方法是表达式 (int)(x + 0.5f)
其中,尽管是incorrect在严格的 IEEE-754 数学中,通常由编译器翻译成正确的 cvtss2si
操作说明。然而,这当然不是一个可移植的假设。
我如何实现一个函数,该函数将使用半对偶语义对任何浮点值进行舍入?如果可能,该函数应仅依赖于语言和标准库语义,以便它可以在非 IEEE 浮点类型上运行。如果这不可能,根据 IEEE-754 位表示定义的答案也是可以接受的。请根据 <limits.h>
描述任何常数或 <limits>
.
最佳答案
The C standard library provides the
round
,lround
, andllround
family of functions in C99. However, these functions are not IEEE-754 compliant, because they do not implement the "banker's rounding" of half-to-even as mandated by IEEE...
谈论某个功能是否“符合 IEEE-754”是没有意义的。 IEEE-754 合规性要求一组具有已定义语义的数据类型操作可用。它不要求那些类型或操作具有特定名称,也不要求仅那些操作可用。一个实现可以提供它想要的任何附加功能并且仍然是兼容的。如果一个实现想要提供舍入到奇数、舍入随机、舍入零和不精确的陷阱,它可以这样做。
IEEE-754 对舍入的实际要求是提供以下六种操作:
convertToIntegerTiesToEven(x)
convertToIntegerTowardZero(x)
convertToIntegerTowardPositive(x)
convertToIntegerTowardNegative(x)
convertToIntegerTiesToAway(x)
convertToIntegerExact(x)
在 C 和 C++ 中,这些操作的最后五个绑定(bind)到 trunc
、ceil
、floor
、round
和 rint
函数。 C11 和 C++14 第一个没有绑定(bind),但 future 的修订将使用 roundeven
。如您所见,round
实际上是必需的操作之一。
但是,roundeven
在当前的实现中不可用,这将我们带到您问题的下一部分:
The usual ad-hoc way to implement rounding in C is the expression
(int)(x + 0.5f)
which, despite being incorrect in strict IEEE-754 math, is usually translated by compilers into the correctcvtss2si
instruction. However, this is certainly not a portable assumption.
该表达式的问题远远超出了“严格的 IEEE-754 数学”。它对负 x
完全不正确,对 nextDown(0.5)
给出错误答案,并将 2**23 binade 中的所有奇数整数转换为偶数整数。任何将它翻译成 cvtss2si
的编译器都非常非常糟糕。如果您有发生这种情况的示例,我很乐意看到。
How can I implement a function that will round any floating point value with half-to-even semantics?
正如 njuffa 在评论中指出的那样,您可以确保设置默认舍入模式并使用 rint
(或 lrint
,因为它听起来您实际上想要一个整数结果),或者您可以通过调用 round
然后像 gnasher729 建议的那样修复中间情况来实现您自己的舍入函数。一旦采用了 C 的 n1778 绑定(bind),您就可以使用 roundeven
或 fromfp
函数执行此操作,而无需控制舍入模式。
关于c++ - 符合 IEEE-754 标准的四舍五入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32746523/