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