我有两个浮点(双)值 a 和 b ,我希望添加它们以获得结果 c 。
我知道 c 会以某种方式被近似,因为一切都是有限的精度。现在,我想要向下舍入' c ,意味着浮点 c 不大于浮点 a 和 b 的实际总和,或 c < = a + b 。
我该怎么做?我想到了以下c代码,但我不确定答案是否符合我的要求。
c = nextafter(a + b, bigNegativeNumber)
同样的问题是乘法而不是加法。 :)
PS。如果有帮助, a 和 b 总是非负数。
编辑: c 也应该是一个浮点
答案 0 :(得分:1)
根据您的描述,您似乎想要控制浮点运算的舍入模式。 C99通过头文件fenv.h
中提供的功能支持此功能。您可能需要指示编译器打开C99支持,您可能需要指示它以符合IEEE-754的方式执行浮点运算。下面是一个最小的示例,显示如何使用截断(向零舍入)执行double
加法。由于您的操作数已知为正数,因此相当于向下舍入(向负无穷大)。
#include <stdio.h>
#include <stdlib.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
double dadd_rz (double a, double b)
{
double res;
int orig_mode = fegetround ();
fesetround (FE_TOWARDZERO); // set rounding mode to truncate
res = a + b;
fesetround (orig_mode); // restore rounding mode
return res;
}
int main (void)
{
double a = 0x1.fffffffffffffp1023;
printf (" a = %20.13a\n", a);
printf (" a+a = %20.13a\n", a + a);
printf ("round_to_zero (a+a) = %20.13a", dadd_rz (a, a));
return EXIT_SUCCESS;
}
上述程序的输出看起来应该是这样的(注意无限的打印是依赖于实现的):
a = 0x1.fffffffffffffp+1023
a+a = 0x1.#INF000000000p+0
round_to_zero (a+a) = 0x1.fffffffffffffp+1023
答案 1 :(得分:0)
棘手的问题。
@EOF上面对“向0舍入”的评论很好并且会提供最佳结果。
#ifdef _ _STDC_IEC_559_ _
fesetround(FE_DOWNWARD);
c = a + b;
#else
#error unable to set rounding mode
#endif
OP的原始方法也很接近。任何好的编译/处理器都应该在0.5或1.0 ULP(取决于舍入模式)下创建最佳答案。它肯定会创建一个总和c2
小于算术a+b
,但c
可能也符合要求。
c = a + b
c2 = nextafter(c, -DBL_MAX);
c = floor(a + b)
无法正常工作,因为a
的数量远远大于某些小的负数b
,因此计算的总和仍然很简单a
并且算术 c <= a + b
。