C标准库在round、lround和llround系列函数中提供C99。然而,这些功能并不符合IEEE-754,因为它们没有按照IEEE的要求实现“银行的四舍五入”。如果分数分量正好为0.5,则半对偶数舍入要求将结果舍入到最近的偶数值。相反,C99标准强制要求从零到一半,就像在cppreference.com上提到的那样。
1-3)计算与arg (浮点格式)最近的整数值,将大小写舍入到零,而不考虑当前的舍入模式。
在C中实现舍入的通常特殊方法是表达式(int)(x + 0.5f),尽管它在严格的IEEE-754数学中是不正确,但通常由编译器将其转换为正确的cvtss2si指令。然而,这肯定不是一个便携的假设。
我如何实现一个函数,使任何浮点值以半对偶数的语义舍入?如果可能的话,该函数应该只依赖于语言和标准库语义,这样才能对非IEEE浮点类型进行操作。如果这是不可能的,以IEEE-754位表示定义的答案也是可以接受的。请用<limits.h>或<limits>描述任何常数。
发布于 2015-09-24 10:49:12
C标准库在
round、lround和llround系列函数中提供C99。然而,这些功能并不符合IEEE-754标准,因为它们没有实现“银行的四舍五入”,即使是IEEE.
谈论单个功能是否符合IEEE-754标准是没有意义的。IEEE-754兼容要求一组具有定义语义的数据类型操作可用。它不要求这些类型或操作具有特定的名称,也不要求只有这些操作可用。实现可以提供它想要的任何附加功能,并且仍然是兼容的。如果一个实现想要提供一次又一次的、随机的、从零到零的四舍五入和陷阱-如果不精确的话,它可以这样做。
IEEE-754实际需要的四舍五入是提供以下六个操作:
convertToIntegerTiesToEven(x) convertToIntegerTowardZero(x) convertToIntegerTowardPositive(x) convertToIntegerTowardNegative(x) convertToIntegerTiesToAway(x) convertToIntegerExact(x)
在C和C++中,最后五个操作分别绑定到trunc、ceil、floor、round和rint函数。C11和C++14对第一个版本没有绑定,但是以后的版本将使用roundeven。如您所见,round实际上是所需的操作之一。
然而,roundeven在当前的实现中是不可用的,这就引出了您问题的下一部分:
在C中实现舍入的通常特殊方法是表达式
(int)(x + 0.5f),尽管严格的IEEE-754数学中不正确,但编译器通常会将其转换为正确的cvtss2si指令。然而,这肯定不是一个便携的假设。
这个表达式的问题远远超出了“严格的IEEE-754数学”。负x完全不正确,给出了错误的nextDown(0.5)答案,并将2**23绑定中的所有奇数转化为偶数整数。任何将其转换为cvtss2si的编译器都会被严重破坏。如果你有这样的例子,我很乐意看到。
我如何实现一个函数,使任何浮点值以半对偶数的语义舍入?
正如njuffa在一条注释中指出的,您可以确保设置了默认舍入模式并使用rint (或lrint,听起来像是您实际上想要一个整数结果),或者您可以通过调用round来实现自己的舍入函数,然后按照gnasher729的建议进行半途而废。一旦采用了C的n1778绑定,您就可以使用roundeven或fromfp函数来执行此操作,而无需控制舍入模式。
发布于 2015-09-23 23:32:13
使用C标准库中的remainder(double x, 1.0)。这与当前的舍入模式无关。
余数函数计算IEC 60559所需的余数x REM。
remainder()在这里很有用,因为它满足OP与偶数需求的联系。
double round_to_nearest_ties_to_even(double x) {
x -= remainder(x, 1.0);
return x;
}测试代码
void rtest(double x) {
double round_half_to_even = round_to_nearest_ties_to_even(x);
printf("x:%25.17le z:%25.17le \n", x, round_half_to_even);
}
void rtest3(double x) {
rtest(nextafter(x, -1.0/0.0));
rtest(x);
rtest(nextafter(x, +1.0/0.0));
}
int main(void) {
rtest3(-DBL_MAX);
rtest3(-2.0);
rtest3(-1.5);
rtest3(-1.0);
rtest3(-0.5);
rtest(nextafter(-0.0, -DBL_MAX));
rtest(-0.0);
rtest(0.0);
rtest(nextafter(0.0, +DBL_MAX));
rtest3(0.5);
rtest3(1.0);
rtest3(1.5);
rtest3(2.0);
rtest3(DBL_MAX);
rtest3(0.0/0.0);
return 0;
}输出
x: -inf z: -inf
x:-1.79769313486231571e+308 z:-1.79769313486231571e+308
x:-1.79769313486231551e+308 z:-1.79769313486231551e+308
x: -2.00000000000000044e+00 z: -2.00000000000000000e+00
x: -2.00000000000000000e+00 z: -2.00000000000000000e+00
x: -1.99999999999999978e+00 z: -2.00000000000000000e+00
x: -1.50000000000000022e+00 z: -2.00000000000000000e+00
x: -1.50000000000000000e+00 z: -2.00000000000000000e+00 tie to even
x: -1.49999999999999978e+00 z: -1.00000000000000000e+00
x: -1.00000000000000022e+00 z: -1.00000000000000000e+00
x: -1.00000000000000000e+00 z: -1.00000000000000000e+00
x: -9.99999999999999889e-01 z: -1.00000000000000000e+00
x: -5.00000000000000111e-01 z: -1.00000000000000000e+00
x: -5.00000000000000000e-01 z: 0.00000000000000000e+00 tie to even
x: -4.99999999999999944e-01 z: 0.00000000000000000e+00
x:-4.94065645841246544e-324 z: 0.00000000000000000e+00
x: -0.00000000000000000e+00 z: 0.00000000000000000e+00
x: 0.00000000000000000e+00 z: 0.00000000000000000e+00
x: 4.94065645841246544e-324 z: 0.00000000000000000e+00
x: 4.99999999999999944e-01 z: 0.00000000000000000e+00
x: 5.00000000000000000e-01 z: 0.00000000000000000e+00 tie to even
x: 5.00000000000000111e-01 z: 1.00000000000000000e+00
x: 9.99999999999999889e-01 z: 1.00000000000000000e+00
x: 1.00000000000000000e+00 z: 1.00000000000000000e+00
x: 1.00000000000000022e+00 z: 1.00000000000000000e+00
x: 1.49999999999999978e+00 z: 1.00000000000000000e+00
x: 1.50000000000000000e+00 z: 2.00000000000000000e+00 tie to even
x: 1.50000000000000022e+00 z: 2.00000000000000000e+00
x: 1.99999999999999978e+00 z: 2.00000000000000000e+00
x: 2.00000000000000000e+00 z: 2.00000000000000000e+00
x: 2.00000000000000044e+00 z: 2.00000000000000000e+00
x: 1.79769313486231551e+308 z: 1.79769313486231551e+308
x: 1.79769313486231571e+308 z: 1.79769313486231571e+308
x: inf z: inf
x: nan z: nan
x: nan z: nan
x: nan z: nan 发布于 2015-09-23 18:13:27
除以数字x,如果x和轮(x)之间的差正好是+0.5或-0.5,而圆(x)是奇数,那么圆(x)是朝错误的方向舍入的,所以从x减去差额。
https://stackoverflow.com/questions/32746523
复制相似问题