C 试图编写一个代码来查找机器epsilon

C 试图编写一个代码来查找机器epsilon,c,floating-point,double,floating-accuracy,C,Floating Point,Double,Floating Accuracy,我试图找出C中各种浮点格式(即浮点、双精度和长双精度)的精度级别。下面是我目前使用的代码: #include <stdio.h> #define N 100000 int main(void) { float max = 1.0, min = 0.0, test; int i; /* Counter for the conditional loop */ for (i = 0; i < N; i++

我试图找出C中各种浮点格式(即浮点、双精度和长双精度)的精度级别。下面是我目前使用的代码:

#include <stdio.h>
#define N 100000

int main(void)
{
   float max = 1.0, min = 0.0, test;
   int i;                              /* Counter for the conditional loop */

   for (i = 0; i < N; i++) {
      test = (max + min) / 2.0;
      if( (1.0 + test) != 1.0)         /* If too high, set max to test and try again */
     max = test;
  if( (1.0 + test) == 1.0)     /* If too low, set min to test and try again */
         min = test;
   }
   printf("The epsilon machine is %.50lf\n", max);
   return 0;
}
#包括
#定义N 100000
内部主(空)
{
浮子最大值=1.0,最小值=0.0,试验;
条件循环的int i;/*计数器*/
对于(i=0;i

这给出了约为~2^-64的预期值。然而,当我将减速改为双倍或“长双倍”时,我得到了相同的答案,我应该得到一个较小的值,但我没有。有人有什么想法吗?

猜猜为什么你会得到同样的答案:

if( (1.0 + test) != 1.0)
这里1.0是一个双精度常数,所以它将浮点数提升为双精度,并作为双精度执行加法。您可能希望在此处声明一个临时浮点以执行加法,或使这些浮点数字常量(
1.0f
IIRC)

在临时浮点中,您可能也会遇到精度过高的问题,可能需要强制它将中间产物存储在内存中,以降低到正确的精度


这里有一个快速重做你的范围搜索方法,但是用正确的类型计算测试。不过,我得到的答案有点太大了

#include <stdio.h>
#define N 100000
#define TYPE float

int main(void)
{
   TYPE max = 1.0, min = 0.0, test;
   int i;

   for (i = 0; i < N; i++)
   {
      TYPE one_plus_test;

      test = (max + min) / ((TYPE)2.0);
      one_plus_test = ((TYPE)1.0) + test;
      if (one_plus_test == ((TYPE)1.0))
      {
         min = test;
      }
      else
      {
         max = test;
      }
   }
   printf("The epsilon machine is %.50lf\n", max);
   return 0;
}
#包括
#定义N 100000
#定义类型浮点
内部主(空)
{
型式最大值=1.0,最小值=0.0,试验;
int i;
对于(i=0;i
我不确定您的算法应该如何工作。这一个(C++)给出了正确的答案:

#include <iostream>

template<typename T>
int epsilon() {
    int pow = 0;
    T eps = 1;
    while (eps + 1 != 1) {
        eps /= 2;
        --pow;
    }
    return pow + 1;
}

int main() {
    std::cout << "Epsilon for float: 2^" << epsilon<float>() << '\n';
    std::cout << "Epsilon for double: 2^" << epsilon<double>() << '\n';
}

这种代码的一个问题是编译器将浮点变量加载到微处理器的浮点寄存器中。如果微处理器只有双精度浮点寄存器,则
float
double
的精度相同


您需要找到一种方法来强制编译器在每两次计算之间将浮点值存储回内存(存储到正确类型的变量中)。这样一来,它就不得不放弃寄存器的额外精度。但是今天的编译器在优化代码方面很聪明。所以这可能很难实现。

这取决于你所说的“精度级别”

浮点数有“常规”(正常)值,但也有特殊的次正常值。如果要找出不同的限制,C标准具有预定义的常数:

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

int main(void)
{
    printf("%30s: %g\n", "FLT_EPSILON", FLT_EPSILON);
    printf("%30s: %g\n", "FLT_MIN", FLT_MIN);
    printf("%30s: %g\n", "nextafterf(0.0, 1.0)", nextafterf(0.0, 1.0));
    printf("%30s: %g\n", "nextafterf(1.0, 2.0)-1", (nextafterf(1.0, 2.0) - 1.0f));
    puts("");
    printf("%30s: %g\n", "DBL_EPSILON", DBL_EPSILON);
    printf("%30s: %g\n", "DBL_MIN", DBL_MIN);
    printf("%30s: %g\n", "nextafter(0.0, 1.0)", nextafter(0.0, 1.0));
    printf("%30s: %g\n", "nextafter(1.0, 2.0)-1", (nextafter(1.0, 2.0) - 1.0));
    puts("");
    printf("%30s: %Lg\n", "LDBL_EPSILON", LDBL_EPSILON);
    printf("%30s: %Lg\n", "LDBL_MIN", LDBL_MIN);
    printf("%30s: %Lg\n", "nextafterl(0.0, 1.0)", nextafterl(0.0, 1.0));
    printf("%30s: %Lg\n", "nextafterl(1.0, 2.0)-1", (nextafterl(1.0, 2.0) - 1.0));
    return 0;
}

我想补充一点,您可以使用
长双精度
从浮点计算中获得最高精度

要将其应用于@Rup的解决方案,只需将
类型
更改为
长双精度
,将
printf
语句更改为:

printf("The epsilon machine is %.50Lf\n", max);
这是我的机器上使用
float
的ε:

0.00000005960465188081798260100185871124267578125000
并使用长双精度

0.00000000000000000005421010862427522170625011179761

差异非常显著。

IEEE 754浮点格式的特性是,当重新解释为相同宽度的2的补码整数时,它们在正值上单调增加,在负值上单调减少(请参见32位浮点的二进制表示)。它们还具有0<| f(x)|<∞, 和| f(x+1)− f(x)|≥ |f(x)− f(x)−1) |(其中f(x)是上述对x的整数重新解释)。在允许类型双关并始终使用IEEE 754-1985的语言中,我们可以利用它在恒定时间内计算机器ε。例如,在C中:

typedef union {
  long long i64;
  double d64;
} dbl_64;

double machine_eps (double value)
{
    dbl_64 s;
    s.d64 = value;
    s.i64++;
    return s.d64 - value;
}

From

float没有23位尾数吗?为什么你会期望2^-64?我如何将其“转换”为浮动?我会试试看会发生什么是的,我试过了,但它仍然给我和ε值2^-64OK,试着把它存储到,然后从一个
volatile float
变量中读取。即:
volatile float tmp=1.0+test;如果(tMP= 1)…< /代码>我不知道任何C++ iFiRiDIT不应该太难理解如果你知道C.模板让我写<代码> t>代码>并替换为<代码>浮点或<代码>双< /代码>。打印的工作方式也不一样,但别担心。干杯,我很高兴C内置了这个功能。然而,我的任务是编写一个代码,找到比一个浮点数更大的最小值。那里的第一个数字:1.19209e-07是我期望的数字,但由于某种原因,我的代码没有给出这个数字。许多的Thanks@Jack:好的。然后,您应该确保计算中使用的所有浮点数都是
float
值。因此,与其做
1.0+测试!=1.0,我会做:
floattry=1.0+测试;如果(try!=1.0)
,诸如此类,那么现在就开始给出合理的答案了,为什么不只是在调试模式或类似模式下编译,而不执行优化呢?
0.00000000000000000005421010862427522170625011179761
typedef union {
  long long i64;
  double d64;
} dbl_64;

double machine_eps (double value)
{
    dbl_64 s;
    s.d64 = value;
    s.i64++;
    return s.d64 - value;
}