(root)/
m4-1.4.19/
tests/
test-float.c
       1  /* Test of <float.h> substitute.
       2     Copyright (C) 2011-2021 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation; either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Written by Bruno Haible <bruno@clisp.org>, 2011.  */
      18  
      19  #include <config.h>
      20  
      21  #include <float.h>
      22  
      23  #include "fpucw.h"
      24  #include "macros.h"
      25  
      26  /* Check that FLT_RADIX is a constant expression.  */
      27  int a[] = { FLT_RADIX };
      28  
      29  #if FLT_RADIX == 2
      30  
      31  /* Return 2^n.  */
      32  static float
      33  pow2f (int n)
      34  {
      35    int k = n;
      36    volatile float x = 1;
      37    volatile float y = 2;
      38    /* Invariant: 2^n == x * y^k.  */
      39    if (k < 0)
      40      {
      41        y = 0.5f;
      42        k = - k;
      43      }
      44    while (k > 0)
      45      {
      46        if (k != 2 * (k / 2))
      47          {
      48            x = x * y;
      49            k = k - 1;
      50          }
      51        if (k == 0)
      52          break;
      53        y = y * y;
      54        k = k / 2;
      55      }
      56    /* Now k == 0, hence x == 2^n.  */
      57    return x;
      58  }
      59  
      60  /* Return 2^n.  */
      61  static double
      62  pow2d (int n)
      63  {
      64    int k = n;
      65    volatile double x = 1;
      66    volatile double y = 2;
      67    /* Invariant: 2^n == x * y^k.  */
      68    if (k < 0)
      69      {
      70        y = 0.5;
      71        k = - k;
      72      }
      73    while (k > 0)
      74      {
      75        if (k != 2 * (k / 2))
      76          {
      77            x = x * y;
      78            k = k - 1;
      79          }
      80        if (k == 0)
      81          break;
      82        y = y * y;
      83        k = k / 2;
      84      }
      85    /* Now k == 0, hence x == 2^n.  */
      86    return x;
      87  }
      88  
      89  /* Return 2^n.  */
      90  static long double
      91  pow2l (int n)
      92  {
      93    int k = n;
      94    volatile long double x = 1;
      95    volatile long double y = 2;
      96    /* Invariant: 2^n == x * y^k.  */
      97    if (k < 0)
      98      {
      99        y = 0.5L;
     100        k = - k;
     101      }
     102    while (k > 0)
     103      {
     104        if (k != 2 * (k / 2))
     105          {
     106            x = x * y;
     107            k = k - 1;
     108          }
     109        if (k == 0)
     110          break;
     111        y = y * y;
     112        k = k / 2;
     113      }
     114    /* Now k == 0, hence x == 2^n.  */
     115    return x;
     116  }
     117  
     118  /* ----------------------- Check macros for 'float' ----------------------- */
     119  
     120  /* Check that the FLT_* macros expand to constant expressions.  */
     121  int fb[] =
     122    {
     123      FLT_MANT_DIG, FLT_MIN_EXP, FLT_MAX_EXP,
     124      FLT_DIG, FLT_MIN_10_EXP, FLT_MAX_10_EXP
     125    };
     126  float fc[] = { FLT_EPSILON, FLT_MIN, FLT_MAX };
     127  
     128  static void
     129  test_float (void)
     130  {
     131    /* Check that the value of FLT_MIN_EXP is well parenthesized.  */
     132    ASSERT ((FLT_MIN_EXP % 101111) == (FLT_MIN_EXP) % 101111);
     133  
     134    /* Check that the value of DBL_MIN_10_EXP is well parenthesized.  */
     135    ASSERT ((FLT_MIN_10_EXP % 101111) == (FLT_MIN_10_EXP) % 101111);
     136  
     137    /* Check that 'float' is as specified in IEEE 754.  */
     138    ASSERT (FLT_MANT_DIG == 24);
     139    ASSERT (FLT_MIN_EXP == -125);
     140    ASSERT (FLT_MAX_EXP == 128);
     141  
     142    /* Check the value of FLT_MIN_10_EXP.  */
     143    ASSERT (FLT_MIN_10_EXP == - (int) (- (FLT_MIN_EXP - 1) * 0.30103));
     144  
     145    /* Check the value of FLT_DIG.  */
     146    ASSERT (FLT_DIG == (int) ((FLT_MANT_DIG - 1) * 0.30103));
     147  
     148    /* Check the value of FLT_MIN_10_EXP.  */
     149    ASSERT (FLT_MIN_10_EXP == - (int) (- (FLT_MIN_EXP - 1) * 0.30103));
     150  
     151    /* Check the value of FLT_MAX_10_EXP.  */
     152    ASSERT (FLT_MAX_10_EXP == (int) (FLT_MAX_EXP * 0.30103));
     153  
     154    /* Check the value of FLT_MAX.  */
     155    {
     156      volatile float m = FLT_MAX;
     157      int n;
     158  
     159      ASSERT (m + m > m);
     160      for (n = 0; n <= 2 * FLT_MANT_DIG; n++)
     161        {
     162          volatile float pow2_n = pow2f (n); /* 2^n */
     163          volatile float x = m + (m / pow2_n);
     164          if (x > m)
     165            ASSERT (x + x == x);
     166          else
     167            ASSERT (!(x + x == x));
     168        }
     169    }
     170  
     171    /* Check the value of FLT_MIN.  */
     172    {
     173      volatile float m = FLT_MIN;
     174      volatile float x = pow2f (FLT_MIN_EXP - 1);
     175      ASSERT (m == x);
     176    }
     177  
     178    /* Check the value of FLT_EPSILON.  */
     179    {
     180      volatile float e = FLT_EPSILON;
     181      volatile float me;
     182      int n;
     183  
     184      me = 1.0f + e;
     185      ASSERT (me > 1.0f);
     186      ASSERT (me - 1.0f == e);
     187      for (n = 0; n <= 2 * FLT_MANT_DIG; n++)
     188        {
     189          volatile float half_n = pow2f (- n); /* 2^-n */
     190          volatile float x = me - half_n;
     191          if (x < me)
     192            ASSERT (x <= 1.0f);
     193        }
     194    }
     195  }
     196  
     197  /* ----------------------- Check macros for 'double' ----------------------- */
     198  
     199  /* Check that the DBL_* macros expand to constant expressions.  */
     200  int db[] =
     201    {
     202      DBL_MANT_DIG, DBL_MIN_EXP, DBL_MAX_EXP,
     203      DBL_DIG, DBL_MIN_10_EXP, DBL_MAX_10_EXP
     204    };
     205  double dc[] = { DBL_EPSILON, DBL_MIN, DBL_MAX };
     206  
     207  static void
     208  test_double (void)
     209  {
     210    /* Check that the value of DBL_MIN_EXP is well parenthesized.  */
     211    ASSERT ((DBL_MIN_EXP % 101111) == (DBL_MIN_EXP) % 101111);
     212  
     213    /* Check that the value of DBL_MIN_10_EXP is well parenthesized.  */
     214    ASSERT ((DBL_MIN_10_EXP % 101111) == (DBL_MIN_10_EXP) % 101111);
     215  
     216    /* Check that 'double' is as specified in IEEE 754.  */
     217    ASSERT (DBL_MANT_DIG == 53);
     218    ASSERT (DBL_MIN_EXP == -1021);
     219    ASSERT (DBL_MAX_EXP == 1024);
     220  
     221    /* Check the value of DBL_MIN_10_EXP.  */
     222    ASSERT (DBL_MIN_10_EXP == - (int) (- (DBL_MIN_EXP - 1) * 0.30103));
     223  
     224    /* Check the value of DBL_DIG.  */
     225    ASSERT (DBL_DIG == (int) ((DBL_MANT_DIG - 1) * 0.30103));
     226  
     227    /* Check the value of DBL_MIN_10_EXP.  */
     228    ASSERT (DBL_MIN_10_EXP == - (int) (- (DBL_MIN_EXP - 1) * 0.30103));
     229  
     230    /* Check the value of DBL_MAX_10_EXP.  */
     231    ASSERT (DBL_MAX_10_EXP == (int) (DBL_MAX_EXP * 0.30103));
     232  
     233    /* Check the value of DBL_MAX.  */
     234    {
     235      volatile double m = DBL_MAX;
     236      int n;
     237  
     238      ASSERT (m + m > m);
     239      for (n = 0; n <= 2 * DBL_MANT_DIG; n++)
     240        {
     241          volatile double pow2_n = pow2d (n); /* 2^n */
     242          volatile double x = m + (m / pow2_n);
     243          if (x > m)
     244            ASSERT (x + x == x);
     245          else
     246            ASSERT (!(x + x == x));
     247        }
     248    }
     249  
     250    /* Check the value of DBL_MIN.  */
     251    {
     252      volatile double m = DBL_MIN;
     253      volatile double x = pow2d (DBL_MIN_EXP - 1);
     254      ASSERT (m == x);
     255    }
     256  
     257    /* Check the value of DBL_EPSILON.  */
     258    {
     259      volatile double e = DBL_EPSILON;
     260      volatile double me;
     261      int n;
     262  
     263      me = 1.0 + e;
     264      ASSERT (me > 1.0);
     265      ASSERT (me - 1.0 == e);
     266      for (n = 0; n <= 2 * DBL_MANT_DIG; n++)
     267        {
     268          volatile double half_n = pow2d (- n); /* 2^-n */
     269          volatile double x = me - half_n;
     270          if (x < me)
     271            ASSERT (x <= 1.0);
     272        }
     273    }
     274  }
     275  
     276  /* -------------------- Check macros for 'long double' -------------------- */
     277  
     278  /* Check that the LDBL_* macros expand to constant expressions.  */
     279  int lb[] =
     280    {
     281      LDBL_MANT_DIG, LDBL_MIN_EXP, LDBL_MAX_EXP,
     282      LDBL_DIG, LDBL_MIN_10_EXP, LDBL_MAX_10_EXP
     283    };
     284  long double lc1 = LDBL_EPSILON;
     285  long double lc2 = LDBL_MIN;
     286  #if 0 /* LDBL_MAX is not a constant expression on some platforms.  */
     287  long double lc3 = LDBL_MAX;
     288  #endif
     289  
     290  static void
     291  test_long_double (void)
     292  {
     293    /* Check that the value of LDBL_MIN_EXP is well parenthesized.  */
     294    ASSERT ((LDBL_MIN_EXP % 101111) == (LDBL_MIN_EXP) % 101111);
     295  
     296    /* Check that the value of LDBL_MIN_10_EXP is well parenthesized.  */
     297    ASSERT ((LDBL_MIN_10_EXP % 101111) == (LDBL_MIN_10_EXP) % 101111);
     298  
     299    /* Check that 'long double' is at least as wide as 'double'.  */
     300    ASSERT (LDBL_MANT_DIG >= DBL_MANT_DIG);
     301    ASSERT (LDBL_MIN_EXP - LDBL_MANT_DIG <= DBL_MIN_EXP - DBL_MANT_DIG);
     302    ASSERT (LDBL_MAX_EXP >= DBL_MAX_EXP);
     303  
     304    /* Check the value of LDBL_DIG.  */
     305    ASSERT (LDBL_DIG == (int)((LDBL_MANT_DIG - 1) * 0.30103));
     306  
     307    /* Check the value of LDBL_MIN_10_EXP.  */
     308    ASSERT (LDBL_MIN_10_EXP == - (int) (- (LDBL_MIN_EXP - 1) * 0.30103));
     309  
     310    /* Check the value of LDBL_MAX_10_EXP.  */
     311    ASSERT (LDBL_MAX_10_EXP == (int) (LDBL_MAX_EXP * 0.30103));
     312  
     313    /* Check the value of LDBL_MAX.  */
     314    {
     315      volatile long double m = LDBL_MAX;
     316      int n;
     317  
     318      ASSERT (m + m > m);
     319      for (n = 0; n <= 2 * LDBL_MANT_DIG; n++)
     320        {
     321          volatile long double pow2_n = pow2l (n); /* 2^n */
     322          volatile long double x = m + (m / pow2_n);
     323          if (x > m)
     324            ASSERT (x + x == x);
     325          else
     326            ASSERT (!(x + x == x));
     327        }
     328    }
     329  
     330    /* Check the value of LDBL_MIN.  */
     331    {
     332      volatile long double m = LDBL_MIN;
     333      volatile long double x = pow2l (LDBL_MIN_EXP - 1);
     334      ASSERT (m == x);
     335    }
     336  
     337    /* Check the value of LDBL_EPSILON.  */
     338    {
     339      volatile long double e = LDBL_EPSILON;
     340      volatile long double me;
     341      int n;
     342  
     343      me = 1.0L + e;
     344      ASSERT (me > 1.0L);
     345      ASSERT (me - 1.0L == e);
     346      for (n = 0; n <= 2 * LDBL_MANT_DIG; n++)
     347        {
     348          volatile long double half_n = pow2l (- n); /* 2^-n */
     349          volatile long double x = me - half_n;
     350          if (x < me)
     351            ASSERT (x <= 1.0L);
     352        }
     353    }
     354  }
     355  
     356  int
     357  main ()
     358  {
     359    test_float ();
     360    test_double ();
     361  
     362    {
     363      DECL_LONG_DOUBLE_ROUNDING
     364  
     365      BEGIN_LONG_DOUBLE_ROUNDING ();
     366  
     367      test_long_double ();
     368  
     369      END_LONG_DOUBLE_ROUNDING ();
     370    }
     371  
     372    return 0;
     373  }
     374  
     375  #else
     376  
     377  int
     378  main ()
     379  {
     380    fprintf (stderr, "Skipping test: FLT_RADIX is not 2.\n");
     381    return 77;
     382  }
     383  
     384  #endif