Blame gnulib-tests/test-float.c

Packit 9e4112
/* Test of <float.h> substitute.
Packit 9e4112
   Copyright (C) 2011-2018 Free Software Foundation, Inc.
Packit 9e4112
Packit 9e4112
   This program is free software: you can redistribute it and/or modify
Packit 9e4112
   it under the terms of the GNU General Public License as published by
Packit 9e4112
   the Free Software Foundation; either version 3 of the License, or
Packit 9e4112
   (at your option) any later version.
Packit 9e4112
Packit 9e4112
   This program is distributed in the hope that it will be useful,
Packit 9e4112
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 9e4112
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 9e4112
   GNU General Public License for more details.
Packit 9e4112
Packit 9e4112
   You should have received a copy of the GNU General Public License
Packit 9e4112
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit 9e4112
Packit 9e4112
/* Written by Bruno Haible <bruno@clisp.org>, 2011.  */
Packit 9e4112
Packit 9e4112
#include <config.h>
Packit 9e4112
Packit 9e4112
#include <float.h>
Packit 9e4112
Packit 9e4112
#include "fpucw.h"
Packit 9e4112
#include "macros.h"
Packit 9e4112
Packit 9e4112
/* Check that FLT_RADIX is a constant expression.  */
Packit 9e4112
int a[] = { FLT_RADIX };
Packit 9e4112
Packit 9e4112
#if FLT_RADIX == 2
Packit 9e4112
Packit 9e4112
/* Return 2^n.  */
Packit 9e4112
static float
Packit 9e4112
pow2f (int n)
Packit 9e4112
{
Packit 9e4112
  int k = n;
Packit 9e4112
  volatile float x = 1;
Packit 9e4112
  volatile float y = 2;
Packit 9e4112
  /* Invariant: 2^n == x * y^k.  */
Packit 9e4112
  if (k < 0)
Packit 9e4112
    {
Packit 9e4112
      y = 0.5f;
Packit 9e4112
      k = - k;
Packit 9e4112
    }
Packit 9e4112
  while (k > 0)
Packit 9e4112
    {
Packit 9e4112
      if (k != 2 * (k / 2))
Packit 9e4112
        {
Packit 9e4112
          x = x * y;
Packit 9e4112
          k = k - 1;
Packit 9e4112
        }
Packit 9e4112
      if (k == 0)
Packit 9e4112
        break;
Packit 9e4112
      y = y * y;
Packit 9e4112
      k = k / 2;
Packit 9e4112
    }
Packit 9e4112
  /* Now k == 0, hence x == 2^n.  */
Packit 9e4112
  return x;
Packit 9e4112
}
Packit 9e4112
Packit 9e4112
/* Return 2^n.  */
Packit 9e4112
static double
Packit 9e4112
pow2d (int n)
Packit 9e4112
{
Packit 9e4112
  int k = n;
Packit 9e4112
  volatile double x = 1;
Packit 9e4112
  volatile double y = 2;
Packit 9e4112
  /* Invariant: 2^n == x * y^k.  */
Packit 9e4112
  if (k < 0)
Packit 9e4112
    {
Packit 9e4112
      y = 0.5;
Packit 9e4112
      k = - k;
Packit 9e4112
    }
Packit 9e4112
  while (k > 0)
Packit 9e4112
    {
Packit 9e4112
      if (k != 2 * (k / 2))
Packit 9e4112
        {
Packit 9e4112
          x = x * y;
Packit 9e4112
          k = k - 1;
Packit 9e4112
        }
Packit 9e4112
      if (k == 0)
Packit 9e4112
        break;
Packit 9e4112
      y = y * y;
Packit 9e4112
      k = k / 2;
Packit 9e4112
    }
Packit 9e4112
  /* Now k == 0, hence x == 2^n.  */
Packit 9e4112
  return x;
Packit 9e4112
}
Packit 9e4112
Packit 9e4112
/* Return 2^n.  */
Packit 9e4112
static long double
Packit 9e4112
pow2l (int n)
Packit 9e4112
{
Packit 9e4112
  int k = n;
Packit 9e4112
  volatile long double x = 1;
Packit 9e4112
  volatile long double y = 2;
Packit 9e4112
  /* Invariant: 2^n == x * y^k.  */
Packit 9e4112
  if (k < 0)
Packit 9e4112
    {
Packit 9e4112
      y = 0.5L;
Packit 9e4112
      k = - k;
Packit 9e4112
    }
Packit 9e4112
  while (k > 0)
Packit 9e4112
    {
Packit 9e4112
      if (k != 2 * (k / 2))
Packit 9e4112
        {
Packit 9e4112
          x = x * y;
Packit 9e4112
          k = k - 1;
Packit 9e4112
        }
Packit 9e4112
      if (k == 0)
Packit 9e4112
        break;
Packit 9e4112
      y = y * y;
Packit 9e4112
      k = k / 2;
Packit 9e4112
    }
Packit 9e4112
  /* Now k == 0, hence x == 2^n.  */
Packit 9e4112
  return x;
Packit 9e4112
}
Packit 9e4112
Packit 9e4112
/* ----------------------- Check macros for 'float' ----------------------- */
Packit 9e4112
Packit 9e4112
/* Check that the FLT_* macros expand to constant expressions.  */
Packit 9e4112
int fb[] =
Packit 9e4112
  {
Packit 9e4112
    FLT_MANT_DIG, FLT_MIN_EXP, FLT_MAX_EXP,
Packit 9e4112
    FLT_DIG, FLT_MIN_10_EXP, FLT_MAX_10_EXP
Packit 9e4112
  };
Packit 9e4112
float fc[] = { FLT_EPSILON, FLT_MIN, FLT_MAX };
Packit 9e4112
Packit 9e4112
static void
Packit 9e4112
test_float (void)
Packit 9e4112
{
Packit 9e4112
  /* Check that the value of FLT_MIN_EXP is well parenthesized.  */
Packit 9e4112
  ASSERT ((FLT_MIN_EXP % 101111) == (FLT_MIN_EXP) % 101111);
Packit 9e4112
Packit 9e4112
  /* Check that the value of DBL_MIN_10_EXP is well parenthesized.  */
Packit 9e4112
  ASSERT ((FLT_MIN_10_EXP % 101111) == (FLT_MIN_10_EXP) % 101111);
Packit 9e4112
Packit 9e4112
  /* Check that 'float' is as specified in IEEE 754.  */
Packit 9e4112
  ASSERT (FLT_MANT_DIG == 24);
Packit 9e4112
  ASSERT (FLT_MIN_EXP == -125);
Packit 9e4112
  ASSERT (FLT_MAX_EXP == 128);
Packit 9e4112
Packit 9e4112
  /* Check the value of FLT_MIN_10_EXP.  */
Packit 9e4112
  ASSERT (FLT_MIN_10_EXP == - (int) (- (FLT_MIN_EXP - 1) * 0.30103));
Packit 9e4112
Packit 9e4112
  /* Check the value of FLT_DIG.  */
Packit 9e4112
  ASSERT (FLT_DIG == (int) ((FLT_MANT_DIG - 1) * 0.30103));
Packit 9e4112
Packit 9e4112
  /* Check the value of FLT_MIN_10_EXP.  */
Packit 9e4112
  ASSERT (FLT_MIN_10_EXP == - (int) (- (FLT_MIN_EXP - 1) * 0.30103));
Packit 9e4112
Packit 9e4112
  /* Check the value of FLT_MAX_10_EXP.  */
Packit 9e4112
  ASSERT (FLT_MAX_10_EXP == (int) (FLT_MAX_EXP * 0.30103));
Packit 9e4112
Packit 9e4112
  /* Check the value of FLT_MAX.  */
Packit 9e4112
  {
Packit 9e4112
    volatile float m = FLT_MAX;
Packit 9e4112
    int n;
Packit 9e4112
Packit 9e4112
    ASSERT (m + m > m);
Packit 9e4112
    for (n = 0; n <= 2 * FLT_MANT_DIG; n++)
Packit 9e4112
      {
Packit 9e4112
        volatile float pow2_n = pow2f (n); /* 2^n */
Packit 9e4112
        volatile float x = m + (m / pow2_n);
Packit 9e4112
        if (x > m)
Packit 9e4112
          ASSERT (x + x == x);
Packit 9e4112
        else
Packit 9e4112
          ASSERT (!(x + x == x));
Packit 9e4112
      }
Packit 9e4112
  }
Packit 9e4112
Packit 9e4112
  /* Check the value of FLT_MIN.  */
Packit 9e4112
  {
Packit 9e4112
    volatile float m = FLT_MIN;
Packit 9e4112
    volatile float x = pow2f (FLT_MIN_EXP - 1);
Packit 9e4112
    ASSERT (m == x);
Packit 9e4112
  }
Packit 9e4112
Packit 9e4112
  /* Check the value of FLT_EPSILON.  */
Packit 9e4112
  {
Packit 9e4112
    volatile float e = FLT_EPSILON;
Packit 9e4112
    volatile float me;
Packit 9e4112
    int n;
Packit 9e4112
Packit 9e4112
    me = 1.0f + e;
Packit 9e4112
    ASSERT (me > 1.0f);
Packit 9e4112
    ASSERT (me - 1.0f == e);
Packit 9e4112
    for (n = 0; n <= 2 * FLT_MANT_DIG; n++)
Packit 9e4112
      {
Packit 9e4112
        volatile float half_n = pow2f (- n); /* 2^-n */
Packit 9e4112
        volatile float x = me - half_n;
Packit 9e4112
        if (x < me)
Packit 9e4112
          ASSERT (x <= 1.0f);
Packit 9e4112
      }
Packit 9e4112
  }
Packit 9e4112
}
Packit 9e4112
Packit 9e4112
/* ----------------------- Check macros for 'double' ----------------------- */
Packit 9e4112
Packit 9e4112
/* Check that the DBL_* macros expand to constant expressions.  */
Packit 9e4112
int db[] =
Packit 9e4112
  {
Packit 9e4112
    DBL_MANT_DIG, DBL_MIN_EXP, DBL_MAX_EXP,
Packit 9e4112
    DBL_DIG, DBL_MIN_10_EXP, DBL_MAX_10_EXP
Packit 9e4112
  };
Packit 9e4112
double dc[] = { DBL_EPSILON, DBL_MIN, DBL_MAX };
Packit 9e4112
Packit 9e4112
static void
Packit 9e4112
test_double (void)
Packit 9e4112
{
Packit 9e4112
  /* Check that the value of DBL_MIN_EXP is well parenthesized.  */
Packit 9e4112
  ASSERT ((DBL_MIN_EXP % 101111) == (DBL_MIN_EXP) % 101111);
Packit 9e4112
Packit 9e4112
  /* Check that the value of DBL_MIN_10_EXP is well parenthesized.  */
Packit 9e4112
  ASSERT ((DBL_MIN_10_EXP % 101111) == (DBL_MIN_10_EXP) % 101111);
Packit 9e4112
Packit 9e4112
  /* Check that 'double' is as specified in IEEE 754.  */
Packit 9e4112
  ASSERT (DBL_MANT_DIG == 53);
Packit 9e4112
  ASSERT (DBL_MIN_EXP == -1021);
Packit 9e4112
  ASSERT (DBL_MAX_EXP == 1024);
Packit 9e4112
Packit 9e4112
  /* Check the value of DBL_MIN_10_EXP.  */
Packit 9e4112
  ASSERT (DBL_MIN_10_EXP == - (int) (- (DBL_MIN_EXP - 1) * 0.30103));
Packit 9e4112
Packit 9e4112
  /* Check the value of DBL_DIG.  */
Packit 9e4112
  ASSERT (DBL_DIG == (int) ((DBL_MANT_DIG - 1) * 0.30103));
Packit 9e4112
Packit 9e4112
  /* Check the value of DBL_MIN_10_EXP.  */
Packit 9e4112
  ASSERT (DBL_MIN_10_EXP == - (int) (- (DBL_MIN_EXP - 1) * 0.30103));
Packit 9e4112
Packit 9e4112
  /* Check the value of DBL_MAX_10_EXP.  */
Packit 9e4112
  ASSERT (DBL_MAX_10_EXP == (int) (DBL_MAX_EXP * 0.30103));
Packit 9e4112
Packit 9e4112
  /* Check the value of DBL_MAX.  */
Packit 9e4112
  {
Packit 9e4112
    volatile double m = DBL_MAX;
Packit 9e4112
    int n;
Packit 9e4112
Packit 9e4112
    ASSERT (m + m > m);
Packit 9e4112
    for (n = 0; n <= 2 * DBL_MANT_DIG; n++)
Packit 9e4112
      {
Packit 9e4112
        volatile double pow2_n = pow2d (n); /* 2^n */
Packit 9e4112
        volatile double x = m + (m / pow2_n);
Packit 9e4112
        if (x > m)
Packit 9e4112
          ASSERT (x + x == x);
Packit 9e4112
        else
Packit 9e4112
          ASSERT (!(x + x == x));
Packit 9e4112
      }
Packit 9e4112
  }
Packit 9e4112
Packit 9e4112
  /* Check the value of DBL_MIN.  */
Packit 9e4112
  {
Packit 9e4112
    volatile double m = DBL_MIN;
Packit 9e4112
    volatile double x = pow2d (DBL_MIN_EXP - 1);
Packit 9e4112
    ASSERT (m == x);
Packit 9e4112
  }
Packit 9e4112
Packit 9e4112
  /* Check the value of DBL_EPSILON.  */
Packit 9e4112
  {
Packit 9e4112
    volatile double e = DBL_EPSILON;
Packit 9e4112
    volatile double me;
Packit 9e4112
    int n;
Packit 9e4112
Packit 9e4112
    me = 1.0 + e;
Packit 9e4112
    ASSERT (me > 1.0);
Packit 9e4112
    ASSERT (me - 1.0 == e);
Packit 9e4112
    for (n = 0; n <= 2 * DBL_MANT_DIG; n++)
Packit 9e4112
      {
Packit 9e4112
        volatile double half_n = pow2d (- n); /* 2^-n */
Packit 9e4112
        volatile double x = me - half_n;
Packit 9e4112
        if (x < me)
Packit 9e4112
          ASSERT (x <= 1.0);
Packit 9e4112
      }
Packit 9e4112
  }
Packit 9e4112
}
Packit 9e4112
Packit 9e4112
/* -------------------- Check macros for 'long double' -------------------- */
Packit 9e4112
Packit 9e4112
/* Check that the LDBL_* macros expand to constant expressions.  */
Packit 9e4112
int lb[] =
Packit 9e4112
  {
Packit 9e4112
    LDBL_MANT_DIG, LDBL_MIN_EXP, LDBL_MAX_EXP,
Packit 9e4112
    LDBL_DIG, LDBL_MIN_10_EXP, LDBL_MAX_10_EXP
Packit 9e4112
  };
Packit 9e4112
long double lc1 = LDBL_EPSILON;
Packit 9e4112
long double lc2 = LDBL_MIN;
Packit 9e4112
#if 0 /* LDBL_MAX is not a constant expression on some platforms.  */
Packit 9e4112
long double lc3 = LDBL_MAX;
Packit 9e4112
#endif
Packit 9e4112
Packit 9e4112
static void
Packit 9e4112
test_long_double (void)
Packit 9e4112
{
Packit 9e4112
  /* Check that the value of LDBL_MIN_EXP is well parenthesized.  */
Packit 9e4112
  ASSERT ((LDBL_MIN_EXP % 101111) == (LDBL_MIN_EXP) % 101111);
Packit 9e4112
Packit 9e4112
  /* Check that the value of LDBL_MIN_10_EXP is well parenthesized.  */
Packit 9e4112
  ASSERT ((LDBL_MIN_10_EXP % 101111) == (LDBL_MIN_10_EXP) % 101111);
Packit 9e4112
Packit 9e4112
  /* Check that 'long double' is at least as wide as 'double'.  */
Packit 9e4112
  ASSERT (LDBL_MANT_DIG >= DBL_MANT_DIG);
Packit 9e4112
  ASSERT (LDBL_MIN_EXP - LDBL_MANT_DIG <= DBL_MIN_EXP - DBL_MANT_DIG);
Packit 9e4112
  ASSERT (LDBL_MAX_EXP >= DBL_MAX_EXP);
Packit 9e4112
Packit 9e4112
  /* Check the value of LDBL_DIG.  */
Packit 9e4112
  ASSERT (LDBL_DIG == (int)((LDBL_MANT_DIG - 1) * 0.30103));
Packit 9e4112
Packit 9e4112
  /* Check the value of LDBL_MIN_10_EXP.  */
Packit 9e4112
  ASSERT (LDBL_MIN_10_EXP == - (int) (- (LDBL_MIN_EXP - 1) * 0.30103));
Packit 9e4112
Packit 9e4112
  /* Check the value of LDBL_MAX_10_EXP.  */
Packit 9e4112
  ASSERT (LDBL_MAX_10_EXP == (int) (LDBL_MAX_EXP * 0.30103));
Packit 9e4112
Packit 9e4112
  /* Check the value of LDBL_MAX.  */
Packit 9e4112
  {
Packit 9e4112
    volatile long double m = LDBL_MAX;
Packit 9e4112
    int n;
Packit 9e4112
Packit 9e4112
    ASSERT (m + m > m);
Packit 9e4112
    for (n = 0; n <= 2 * LDBL_MANT_DIG; n++)
Packit 9e4112
      {
Packit 9e4112
        volatile long double pow2_n = pow2l (n); /* 2^n */
Packit 9e4112
        volatile long double x = m + (m / pow2_n);
Packit 9e4112
        if (x > m)
Packit 9e4112
          ASSERT (x + x == x);
Packit 9e4112
        else
Packit 9e4112
          ASSERT (!(x + x == x));
Packit 9e4112
      }
Packit 9e4112
  }
Packit 9e4112
Packit 9e4112
  /* Check the value of LDBL_MIN.  */
Packit 9e4112
  {
Packit 9e4112
    volatile long double m = LDBL_MIN;
Packit 9e4112
    volatile long double x = pow2l (LDBL_MIN_EXP - 1);
Packit 9e4112
    ASSERT (m == x);
Packit 9e4112
  }
Packit 9e4112
Packit 9e4112
  /* Check the value of LDBL_EPSILON.  */
Packit 9e4112
  {
Packit 9e4112
    volatile long double e = LDBL_EPSILON;
Packit 9e4112
    volatile long double me;
Packit 9e4112
    int n;
Packit 9e4112
Packit 9e4112
    me = 1.0L + e;
Packit 9e4112
    ASSERT (me > 1.0L);
Packit 9e4112
    ASSERT (me - 1.0L == e);
Packit 9e4112
    for (n = 0; n <= 2 * LDBL_MANT_DIG; n++)
Packit 9e4112
      {
Packit 9e4112
        volatile long double half_n = pow2l (- n); /* 2^-n */
Packit 9e4112
        volatile long double x = me - half_n;
Packit 9e4112
        if (x < me)
Packit 9e4112
          ASSERT (x <= 1.0L);
Packit 9e4112
      }
Packit 9e4112
  }
Packit 9e4112
}
Packit 9e4112
Packit 9e4112
int
Packit 9e4112
main ()
Packit 9e4112
{
Packit 9e4112
  test_float ();
Packit 9e4112
  test_double ();
Packit 9e4112
Packit 9e4112
  {
Packit 9e4112
    DECL_LONG_DOUBLE_ROUNDING
Packit 9e4112
Packit 9e4112
    BEGIN_LONG_DOUBLE_ROUNDING ();
Packit 9e4112
Packit 9e4112
    test_long_double ();
Packit 9e4112
Packit 9e4112
    END_LONG_DOUBLE_ROUNDING ();
Packit 9e4112
  }
Packit 9e4112
Packit 9e4112
  return 0;
Packit 9e4112
}
Packit 9e4112
Packit 9e4112
#else
Packit 9e4112
Packit 9e4112
int
Packit 9e4112
main ()
Packit 9e4112
{
Packit 9e4112
  fprintf (stderr, "Skipping test: FLT_RADIX is not 2.\n");
Packit 9e4112
  return 77;
Packit 9e4112
}
Packit 9e4112
Packit 9e4112
#endif