Trying to write epsilon machine search code

I am trying to figure out the level of accuracy for various floating point formats in C (i.e. float, double and long double). Here is the code I'm currently using:

#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;
}

This gives a value of about ~ 2 ^ -64, as expected. However, when I change the deceleration to double or "doubles", I get the same answer as getting less value, but I do not. Does anyone have any ideas?

+5
source share
6 answers

Guess why you get the same answer:

if( (1.0 + test) != 1.0)

1.0 - , float double . , float (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;
}
+2

, " ".

"" () , , . , 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;
}

4 :

  • 1 1 (TYPE _EPSILON),
  • (TYPE _MIN). ,
  • (nextafter * (0... )). ,
  • , 1. , TYPE _EPSILON, -.

, "", .

:

               FLT_EPSILON: 1.19209e-07
                   FLT_MIN: 1.17549e-38
      nextafterf(0.0, 1.0): 1.4013e-45
    nextafterf(1.0, 2.0)-1: 1.19209e-07

               DBL_EPSILON: 2.22045e-16
                   DBL_MIN: 2.22507e-308
       nextafter(0.0, 1.0): 4.94066e-324
     nextafter(1.0, 2.0)-1: 2.22045e-16

              LDBL_EPSILON: 1.0842e-19
                  LDBL_MIN: 3.3621e-4932
      nextafterl(0.0, 1.0): 3.6452e-4951
    nextafterl(1.0, 2.0)-1: 1.0842e-19
+8

, . (++) :

#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';
}

, , 1 1.

:

Epsilon for float: 2^-23
Epsilon for double: 2^-52
+2

IEEE 754 , (. 32- ). , 0 < | () | < ∞ | f (x + 1) - f (x) | ≥ | f (x) - f (x-1) | ( f (x) - x). , IEEE 754-1985, epsilon . , 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;
}

https://en.wikipedia.org/wiki/Machine_epsilon

+2

, , long double.

@Rup, TYPE long double printf :

printf("The epsilon machine is %.50Lf\n", max);

Epsilon , float:

0.00000005960465188081798260100185871124267578125000

long double:

0.00000000000000000005421010862427522170625011179761

.

+1

, . , float double.

You need to find a way to force the compiler to store the floating point value back into memory between every two calculations (into a variable of the correct type). Thus, it should discard the extra precision of the registers. But today, compilers are able to optimize your code. Thus, this can be difficult to achieve.

0
source

All Articles