【问题标题】:Round Down a Floating Point Result舍入浮点结果
【发布时间】:2015-07-15 23:33:32
【问题描述】:

我有两个浮点(双精度)值 ab,我希望将它们相加以获得结果 c .

我知道 c 会以某种方式近似,因为一切都是有限精度。现在,我想“向下取整”c,这意味着浮点 c 不大于浮点 ab,或 c a + b.

我该怎么做?想到以下c中的代码,但我不确定答案是否是我想要的。

c = nextafter(a + b, bigNegativeNumber)

同样的问题也适用于乘法而不是加法。 :)

PS。如果有帮助,ab 始终是非负数。

编辑:c 也应该是一个浮点数

【问题讨论】:

  • 如果 c 是整数类型,那么你可以直接转换
  • 至少在某些架构上,您可以将舍入模式设置为向零或负无穷大舍入:IEEE 754 1985: 4.2. Directed Roundings An implementation shall also provide three user-selectable directed rounding modes: round toward +INFINITY, round toward – INFINITY, and round toward 0.
  • 与风向标相同,但路线更长,c = floor(-1 * (a + b))*-1;如果小数四舍五入有问题。
  • @user3528438 它是浮点类型,而不是整数。如果它是整数,那么一开始就没有问题。
  • @WeatherVane 我编辑了帖子,我有兴趣找到一个浮点值,而不是整数。抱歉含糊其辞。

标签: c floating-point double rounding


【解决方案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

【讨论】:

    【解决方案2】:

    一个棘手的问题。

    @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 并且 算术 @987654331 失败@。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-03
      • 1970-01-01
      相关资源
      最近更新 更多