向下舍入浮点结果
Round Down a Floating Point Result
我有两个浮点(双精度)值 a 和 b,我希望将它们相加以获得结果c。
我知道 c 会以某种方式被近似,因为一切都是有限精度的。现在,我要'round down'c,意思是浮点数c不大于浮点数的实数和a 和 b,或 c <= a + b.
我该怎么做?想到了下面c中的代码,但我不确定答案是否是我想要的。
c = nextafter(a + b, bigNegativeNumber)
相同的问题适用于乘法而不是加法。 :)
PS。如果有帮助,a 和 b 总是非负数。
编辑:c 也应该是一个浮点数
根据您的描述,您似乎想控制浮点运算的舍入模式。头文件 fenv.h
中提供的功能在 C99 中支持这一点。您可能需要指示您的编译器打开 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
一个棘手的问题。
@EOF 上面对 "round toward 0" 的评论很好,将提供最佳结果。
#ifdef _ _STDC_IEC_559_ _
fesetround(FE_DOWNWARD);
c = a + b;
#else
#error unable to set rounding mode
#endif
OP的原始方法也很接近。任何好的 compilation/processor 都应该在 0.5 或 1.0 ULP(取决于舍入模式)中为 with 创建最佳答案。它肯定会创建一个总和 c2
小于算术 a+b
,但是 c
可能 也满足要求。
c = a + b
c2 = nextafter(c, -DBL_MAX);
c = floor(a + b)
将不起作用,因为 a
的幅度可能远大于一些小的负值 b
,因此计算的总和仍然很简单 a
并且失败算术 c <= a + b
.
我有两个浮点(双精度)值 a 和 b,我希望将它们相加以获得结果c。
我知道 c 会以某种方式被近似,因为一切都是有限精度的。现在,我要'round down'c,意思是浮点数c不大于浮点数的实数和a 和 b,或 c <= a + b.
我该怎么做?想到了下面c中的代码,但我不确定答案是否是我想要的。
c = nextafter(a + b, bigNegativeNumber)
相同的问题适用于乘法而不是加法。 :)
PS。如果有帮助,a 和 b 总是非负数。
编辑:c 也应该是一个浮点数
根据您的描述,您似乎想控制浮点运算的舍入模式。头文件 fenv.h
中提供的功能在 C99 中支持这一点。您可能需要指示您的编译器打开 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
一个棘手的问题。
@EOF 上面对 "round toward 0" 的评论很好,将提供最佳结果。
#ifdef _ _STDC_IEC_559_ _
fesetround(FE_DOWNWARD);
c = a + b;
#else
#error unable to set rounding mode
#endif
OP的原始方法也很接近。任何好的 compilation/processor 都应该在 0.5 或 1.0 ULP(取决于舍入模式)中为 with 创建最佳答案。它肯定会创建一个总和 c2
小于算术 a+b
,但是 c
可能 也满足要求。
c = a + b
c2 = nextafter(c, -DBL_MAX);
c = floor(a + b)
将不起作用,因为 a
的幅度可能远大于一些小的负值 b
,因此计算的总和仍然很简单 a
并且失败算术 c <= a + b
.