如何降低C中双精度?

时间:2017-12-19 21:51:41

标签: floating-point double precision

我正在尝试降低C中double变量的精度,以测试对结果的影响。我尝试按位&,但它给出了一个错误。

如何在floatdouble变量上执行此操作?

2 个答案:

答案 0 :(得分:0)

如果您希望应用按位和&,则需要将其应用于float值的整数表示:

float f = 0.1f;
printf("Befor: %a %.16e\n", f, f);
unsigned int i;
_Static_assert(sizeof f == sizeof i, "pick integer type of the correct size");
memcpy(&i, &f, sizeof i);
i &= ~ 0x3U; // or any other mask.
            // This one assumes the endianness of floats is identical to integers'
memcpy(&f, &i, sizeof f);
printf("After: %a %.16e\n", f, f);

请注意,这不会为您提供类似29位IEEE-754的数字。 f中的值首先舍入为32位单精度数,然后被残酷地截断。

更优雅的方法依赖于设置了两位的浮点常量:

float f = 0.1f;
float factor = 5.0f; // or 3, or 9, or 17
float c = factor * f;
f = c - (c - f);
printf("After: %a %.16e\n", f, f);

这种方法的优点是它使用N位有效数将f舍入到最接近的值,而不是像第一种方法那样将其截断为零。但是,该程序仍在使用32位IEEE 754浮点计算,然后舍入到较少的位,因此结果仍然不等于较窄的浮点类型产生的结果。

第二种方法依赖于Dekker的想法,在this article在线描述。

答案 1 :(得分:0)

  

如何降低C中双精度?

为了降低浮点数的相对精度,使significand/mantissa的各个最低有效位为零,代码需要访问有效数字。

使用frexp()提取FP编号的符号和指数。

使用ldexp()对符号进行缩放,然后根据编码目标舍入,截断或放置 - 以消除精度。显示截断,但我建议通过rint()

进行舍入

缩小并添加指数。

#include <math.h>
#include <stdio.h>

double reduce(double x, int precision_power_2) {
  if (isfinite(x)) {
    int power_2;

    // The frexp functions break a floating-point number into a 
    // normalized fraction and an integral power of 2.
    double normalized_fraction = frexp(x, &power_2);  // 0.5 <= result < 1.0 or 0

    // The ldexp functions multiply a floating-point number by an integral power of 2
   double less_precise = trunc(ldexp(normalized_fraction, precision_power_2));
   x = ldexp(less_precise, power_2 - precision_power_2);

  }
  return x;
}

void testr(double x, int pow2) {
  printf("reduce(%a, %d --> %a\n", x, pow2, reduce(x, pow2));
}

int main(void) {
  testr(0.1, 5);
  return 0;
}

输出

//       v-53 bin.digs-v             v-v 5 significant binary digits  
reduce(0x1.999999999999ap-4, 5 --> 0x1.9p-4

frexpf()使用ldexp()rintf()truncf()floorf()float等。