C标准库在C99中提供了round
、lround
和llround
系列函数。然而,这些函数不符合IEEE-754,因为它们没有实现IEEE所要求的半到偶数的“银行舍入”。如果小数部分正好为0.5,则半偶数舍入要求将结果舍入到最接近的偶数值。相反,C99标准要求使用与零相差一半的值,如cppreference.com上所示
1-3)计算最接近arg的整数值(浮点格式),将大小写从零舍入一半,而不考虑目前的舍入模式。
在C语言中实现舍入的通常的特别方法是表达式(int)(x + 0.5f)
,尽管在严格的IEEE-754数学中是incorrect,但通常由编译器翻译成正确的cvtss2si
指令。然而,这肯定不是一个可移植的假设。
我如何实现一个函数,将舍入任何浮点值与半到偶数的语义?如果可能的话,函数应该只依赖于语言和标准库语义,这样它就可以在非IEEE浮点类型上操作。如果这是不可能的,则根据IEEE-754位表示定义的答案也是可接受的。请用<limits.h>
或<limits>
来表征任何常数。
6条答案
按热度按时间juud5qan1#
C标准库在C99中提供了
round
、lround
和llround
系列函数。但是,这些函数不符合IEEE-754,因为它们不实现IEEE...讨论某个函数是否“符合IEEE-754”是没有意义的。IEEE-754兼容性要求具有定义的语义的一组数据类型操作是可用的。它不要求这些类型或操作具有特定的名称,也不要求 * 仅 * 这些操作可用。一个实现可以提供它想要的任何附加功能,并且仍然是兼容的。如果一个实现想要提供舍入到奇数、随机舍入、远离零的舍入和不精确时的陷阱,它可以这样做。
IEEE-754实际上对舍入的要求是提供以下六种操作:
转换为整数阶转换为偶数阶(x)
向零方向转换为整数(x)
转换为正整数(x)
向负整数转换(x)
转换为整数等待时间(x)
转换为整数精确值(x)
在C和C中,这些运算的最后五个分别绑定到
trunc
、ceil
、floor
、round
和rint
函数。C11和C14对于第一个版本没有绑定,但未来的版本将使用roundeven
。如您所见,round
实际上是必需的操作之一。但是,
roundeven
在当前的实现中不可用,这就引出了您问题的下一部分:在C语言中实现舍入的通常的特别方法是表达式
(int)(x + 0.5f)
,尽管在严格的IEEE-754数学中是不正确的,但通常由编译器翻译成正确的cvtss2si
指令。然而,这肯定不是一个可移植的假设。该表达式的问题远远超出了“严格的IEEE-754数学”。它对于负数
x
是完全不正确的,对于nextDown(0.5)
给出了错误的答案,并将223 binade中的所有奇数都变成了偶数。任何将其翻译成cvtss2si
的编译器都是可怕的,可怕的坏掉了。如果你有这样的例子,我很乐意看到。我如何实现一个函数,将舍入任何浮点值与半到偶数的语义?
正如njuffa在注解中所指出的,您可以确保设置了默认的舍入模式,并使用
rint
(或lrint
,因为听起来您实际上想要一个整数结果),或者您可以通过调用round
来实现您自己的舍入函数,然后像gnasher 729**建议的那样修正中途情况。一旦采用了C语言的n1778绑定,就可以使用roundeven
或fromfp
函数来执行此操作,而无需控制舍入模式。vom3gejh2#
使用C标准库中的
remainder(double x, 1.0)
。这与电流舍入模式无关。余数函数计算IEC 60559所需的余数x REM y
remainder()
在这里很有用,因为它满足了OP对偶数的要求。字符串
测试代码
型
产出
型
fcg9iug33#
对数字x进行舍入,如果x和round(x)之间的差正好是+0.5或-0.5,并且round(x)是奇数,则round(x)的舍入方向错误,因此要从x中减去差值。
amrnrhlw4#
float
数据类型可以表示8388608.0f到16777216.0f范围内的所有整数,但不能表示分数。任何大于8388607.5f的float
数字都是整数,不需要四舍五入。将8388608.0f与任何小于该值的非负float
相加,将产生一个整数,该整数将根据当前舍入模式(通常为舍入半到偶数)进行舍入。然后减去8388608.0f将产生原始的适当舍入版本(假设它在合适的范围内)。因此,应该可以执行以下操作:
字符串
并且利用加法的自然舍入行为,而不必使用任何其它“舍入到整数”工具。
mzmfm0qo5#
从C++11开始,STL中有一个函数可以进行半偶数舍入。如果浮点舍入模式设置为
FE_TONEAREST
(默认值),那么std::nearbyint
就可以完成任务。C++ Reference for std::nearbyint
iugsix8n6#
以下是舍入半到偶数程序的简单实现,它遵循IEEE舍入标准。
**逻辑:**error = 0.00001
1.数量=2.5
1.x= -1 + temp = -1
**注意:**这里的误差为0.00001,即如果出现2.500001,则四舍五入为2而不是3
Python 2.7实现:
字符串
C++实现:(floor函数使用 math.h)
型
这将给予的输出将如下acc。标准:
(3.5)-> 4
(2.5)-> 2
**编辑1:**正如@Mark Dickinson在评论中指出的那样。可以根据需要在代码中修改错误以使其标准化。对于python,要将其转换为最小的float值,您可以执行以下操作。
型