Home | History | Annotate | Line # | Download | only in mpn
t-get_d.c revision 1.1.1.1.8.1
      1 /* Test mpn_get_d.
      2 
      3 Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
      4 
      5 This file is part of the GNU MP Library test suite.
      6 
      7 The GNU MP Library test suite is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 3 of the License,
     10 or (at your option) any later version.
     11 
     12 The GNU MP Library test suite is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
     15 Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License along with
     18 the GNU MP Library test suite.  If not, see http://www.gnu.org/licenses/.  */
     19 
     20 /* Note that we don't use <limits.h> for LONG_MIN, but instead our own
     21    definition in gmp-impl.h.  In gcc 2.95.4 (debian 3.0) under
     22    -mcpu=ultrasparc, limits.h sees __sparc_v9__ defined and assumes that
     23    means long is 64-bit long, but it's only 32-bits, causing fatal compile
     24    errors.  */
     25 
     26 #include "config.h"
     27 
     28 #include <setjmp.h>
     29 #include <signal.h>
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 
     33 #include "gmp.h"
     34 #include "gmp-impl.h"
     35 #include "tests.h"
     36 
     37 
     38 #ifndef _GMP_IEEE_FLOATS
     39 #define _GMP_IEEE_FLOATS 0
     40 #endif
     41 
     42 
     43 /* Exercise various 2^n values, with various exponents and positive and
     44    negative.  */
     45 void
     46 check_onebit (void)
     47 {
     48   static const int bit_table[] = {
     49     0, 1, 2, 3,
     50     GMP_NUMB_BITS - 2, GMP_NUMB_BITS - 1,
     51     GMP_NUMB_BITS,
     52     GMP_NUMB_BITS + 1, GMP_NUMB_BITS + 2,
     53     2 * GMP_NUMB_BITS - 2, 2 * GMP_NUMB_BITS - 1,
     54     2 * GMP_NUMB_BITS,
     55     2 * GMP_NUMB_BITS + 1, 2 * GMP_NUMB_BITS + 2,
     56     3 * GMP_NUMB_BITS - 2, 3 * GMP_NUMB_BITS - 1,
     57     3 * GMP_NUMB_BITS,
     58     3 * GMP_NUMB_BITS + 1, 3 * GMP_NUMB_BITS + 2,
     59     4 * GMP_NUMB_BITS - 2, 4 * GMP_NUMB_BITS - 1,
     60     4 * GMP_NUMB_BITS,
     61     4 * GMP_NUMB_BITS + 1, 4 * GMP_NUMB_BITS + 2,
     62     5 * GMP_NUMB_BITS - 2, 5 * GMP_NUMB_BITS - 1,
     63     5 * GMP_NUMB_BITS,
     64     5 * GMP_NUMB_BITS + 1, 5 * GMP_NUMB_BITS + 2,
     65     6 * GMP_NUMB_BITS - 2, 6 * GMP_NUMB_BITS - 1,
     66     6 * GMP_NUMB_BITS,
     67     6 * GMP_NUMB_BITS + 1, 6 * GMP_NUMB_BITS + 2,
     68   };
     69   static const int exp_table[] = {
     70     0, -100, -10, -1, 1, 10, 100,
     71   };
     72 
     73   /* FIXME: It'd be better to base this on the float format. */
     74 #if defined (__vax) || defined (__vax__)
     75   int     limit = 127;  /* vax fp numbers have limited range */
     76 #else
     77   int     limit = 511;
     78 #endif
     79 
     80   int        bit_i, exp_i, i;
     81   double     got, want;
     82   mp_size_t  nsize, sign;
     83   long       bit, exp, want_bit;
     84   mp_limb_t  np[20];
     85 
     86   for (bit_i = 0; bit_i < numberof (bit_table); bit_i++)
     87     {
     88       bit = bit_table[bit_i];
     89 
     90       nsize = BITS_TO_LIMBS (bit+1);
     91       refmpn_zero (np, nsize);
     92       np[bit/GMP_NUMB_BITS] = CNST_LIMB(1) << (bit % GMP_NUMB_BITS);
     93 
     94       for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
     95         {
     96           exp = exp_table[exp_i];
     97 
     98           want_bit = bit + exp;
     99           if (want_bit >= limit || want_bit <= -limit)
    100             continue;
    101 
    102           want = 1.0;
    103           for (i = 0; i < want_bit; i++)
    104             want *= 2.0;
    105           for (i = 0; i > want_bit; i--)
    106             want *= 0.5;
    107 
    108           for (sign = 0; sign >= -1; sign--, want = -want)
    109             {
    110               got = mpn_get_d (np, nsize, sign, exp);
    111               if (got != want)
    112                 {
    113                   printf    ("mpn_get_d wrong on 2^n\n");
    114                   printf    ("   bit      %ld\n", bit);
    115                   printf    ("   exp      %ld\n", exp);
    116                   printf    ("   want_bit %ld\n", want_bit);
    117                   printf    ("   sign     %ld\n", (long) sign);
    118                   mpn_trace ("   n        ", np, nsize);
    119                   printf    ("   nsize    %ld\n", (long) nsize);
    120                   d_trace   ("   want     ", want);
    121                   d_trace   ("   got      ", got);
    122                   abort();
    123                 }
    124             }
    125         }
    126     }
    127 }
    128 
    129 
    130 /* Exercise values 2^n+1, while such a value fits the mantissa of a double. */
    131 void
    132 check_twobit (void)
    133 {
    134   int        i, mant_bits;
    135   double     got, want;
    136   mp_size_t  nsize, sign;
    137   mp_ptr     np;
    138 
    139   mant_bits = tests_dbl_mant_bits ();
    140   if (mant_bits == 0)
    141     return;
    142 
    143   np = refmpn_malloc_limbs (BITS_TO_LIMBS (mant_bits));
    144   want = 3.0;
    145   for (i = 1; i < mant_bits; i++)
    146     {
    147       nsize = BITS_TO_LIMBS (i+1);
    148       refmpn_zero (np, nsize);
    149       np[i/GMP_NUMB_BITS] = CNST_LIMB(1) << (i % GMP_NUMB_BITS);
    150       np[0] |= 1;
    151 
    152       for (sign = 0; sign >= -1; sign--)
    153         {
    154           got = mpn_get_d (np, nsize, sign, 0);
    155           if (got != want)
    156             {
    157               printf    ("mpn_get_d wrong on 2^%d + 1\n", i);
    158               printf    ("   sign     %ld\n", (long) sign);
    159               mpn_trace ("   n        ", np, nsize);
    160               printf    ("   nsize    %ld\n", (long) nsize);
    161               d_trace   ("   want     ", want);
    162               d_trace   ("   got      ", got);
    163               abort();
    164             }
    165           want = -want;
    166         }
    167 
    168       want = 2.0 * want - 1.0;
    169     }
    170 
    171   free (np);
    172 }
    173 
    174 
    175 /* Expect large negative exponents to underflow to 0.0.
    176    Some systems might have hardware traps for such an underflow (though
    177    usually it's not the default), so watch out for SIGFPE. */
    178 void
    179 check_underflow (void)
    180 {
    181   static const long exp_table[] = {
    182     -999999L, LONG_MIN,
    183   };
    184   static const mp_limb_t  np[1] = { 1 };
    185 
    186   static long exp;
    187   mp_size_t  nsize, sign;
    188   double     got;
    189   int        exp_i;
    190 
    191   nsize = numberof (np);
    192 
    193   if (tests_setjmp_sigfpe() == 0)
    194     {
    195       for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
    196         {
    197           exp = exp_table[exp_i];
    198 
    199           for (sign = 0; sign >= -1; sign--)
    200             {
    201               got = mpn_get_d (np, nsize, sign, exp);
    202               if (got != 0.0)
    203                 {
    204                   printf  ("mpn_get_d wrong, didn't get 0.0 on underflow\n");
    205                   printf  ("  nsize    %ld\n", (long) nsize);
    206                   printf  ("  exp      %ld\n", exp);
    207                   printf  ("  sign     %ld\n", (long) sign);
    208                   d_trace ("  got      ", got);
    209                   abort ();
    210                 }
    211             }
    212         }
    213     }
    214   else
    215     {
    216       printf ("Warning, underflow to zero tests skipped due to SIGFPE (exp=%ld)\n", exp);
    217     }
    218   tests_sigfpe_done ();
    219 }
    220 
    221 
    222 /* Expect large values to result in +/-inf, on IEEE systems. */
    223 void
    224 check_inf (void)
    225 {
    226   static const long exp_table[] = {
    227     999999L, LONG_MAX,
    228   };
    229   static const mp_limb_t  np[4] = { 1, 1, 1, 1 };
    230   long       exp;
    231   mp_size_t  nsize, sign, got_sign;
    232   double     got;
    233   int        exp_i;
    234 
    235   if (! _GMP_IEEE_FLOATS)
    236     return;
    237 
    238   for (nsize = 1; nsize <= numberof (np); nsize++)
    239     {
    240       for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
    241         {
    242           exp = exp_table[exp_i];
    243 
    244           for (sign = 0; sign >= -1; sign--)
    245             {
    246               got = mpn_get_d (np, nsize, sign, exp);
    247               got_sign = (got >= 0 ? 0 : -1);
    248               if (! tests_isinf (got))
    249                 {
    250                   printf  ("mpn_get_d wrong, didn't get infinity\n");
    251                 bad:
    252                   printf  ("  nsize    %ld\n", (long) nsize);
    253                   printf  ("  exp      %ld\n", exp);
    254                   printf  ("  sign     %ld\n", (long) sign);
    255                   d_trace ("  got      ", got);
    256                   printf  ("  got sign %ld\n", (long) got_sign);
    257                   abort ();
    258                 }
    259               if (got_sign != sign)
    260                 {
    261                   printf  ("mpn_get_d wrong sign on infinity\n");
    262                   goto bad;
    263                 }
    264             }
    265         }
    266     }
    267 }
    268 
    269 /* Check values 2^n approaching and into IEEE denorm range.
    270    Some systems might not support denorms, or might have traps setup, so
    271    watch out for SIGFPE.  */
    272 void
    273 check_ieee_denorm (void)
    274 {
    275   static long exp;
    276   mp_limb_t  n = 1;
    277   long       i;
    278   mp_size_t  sign;
    279   double     want, got;
    280 
    281   if (! _GMP_IEEE_FLOATS)
    282     return;
    283 
    284   if (tests_setjmp_sigfpe() == 0)
    285     {
    286       exp = -1020;
    287       want = 1.0;
    288       for (i = 0; i > exp; i--)
    289         want *= 0.5;
    290 
    291       for ( ; exp > -1500 && want != 0.0; exp--)
    292         {
    293           for (sign = 0; sign >= -1; sign--)
    294             {
    295               got = mpn_get_d (&n, (mp_size_t) 1, sign, exp);
    296               if (got != want)
    297                 {
    298                   printf  ("mpn_get_d wrong on denorm\n");
    299                   printf  ("  n=1\n");
    300                   printf  ("  exp   %ld\n", exp);
    301                   printf  ("  sign  %ld\n", (long) sign);
    302                   d_trace ("  got   ", got);
    303                   d_trace ("  want  ", want);
    304                   abort ();
    305                 }
    306               want = -want;
    307             }
    308           want *= 0.5;
    309           FORCE_DOUBLE (want);
    310         }
    311     }
    312   else
    313     {
    314       printf ("Warning, IEEE denorm tests skipped due to SIGFPE (exp=%ld)\n", exp);
    315     }
    316   tests_sigfpe_done ();
    317 }
    318 
    319 
    320 /* Check values 2^n approaching exponent overflow.
    321    Some systems might trap on overflow, so watch out for SIGFPE.  */
    322 void
    323 check_ieee_overflow (void)
    324 {
    325   static long exp;
    326   mp_limb_t  n = 1;
    327   long       i;
    328   mp_size_t  sign;
    329   double     want, got;
    330 
    331   if (! _GMP_IEEE_FLOATS)
    332     return;
    333 
    334   if (tests_setjmp_sigfpe() == 0)
    335     {
    336       exp = 1010;
    337       want = 1.0;
    338       for (i = 0; i < exp; i++)
    339         want *= 2.0;
    340 
    341       for ( ; exp < 1050; exp++)
    342         {
    343           for (sign = 0; sign >= -1; sign--)
    344             {
    345               got = mpn_get_d (&n, (mp_size_t) 1, sign, exp);
    346               if (got != want)
    347                 {
    348                   printf  ("mpn_get_d wrong on overflow\n");
    349                   printf  ("  n=1\n");
    350                   printf  ("  exp   %ld\n", exp);
    351                   printf  ("  sign  %ld\n", (long) sign);
    352                   d_trace ("  got   ", got);
    353                   d_trace ("  want  ", want);
    354                   abort ();
    355                 }
    356               want = -want;
    357             }
    358           want *= 2.0;
    359           FORCE_DOUBLE (want);
    360         }
    361     }
    362   else
    363     {
    364       printf ("Warning, IEEE overflow tests skipped due to SIGFPE (exp=%ld)\n", exp);
    365     }
    366   tests_sigfpe_done ();
    367 }
    368 
    369 
    370 /* ARM gcc 2.95.4 was seen generating bad code for ulong->double
    371    conversions, resulting in for instance 0x81c25113 incorrectly converted.
    372    This test exercises that value, to see mpn_get_d has avoided the
    373    problem.  */
    374 void
    375 check_0x81c25113 (void)
    376 {
    377 #if GMP_NUMB_BITS >= 32
    378   double     want = 2176995603.0;
    379   double     got;
    380   mp_limb_t  np[4];
    381   mp_size_t  nsize;
    382   long       exp;
    383 
    384   if (tests_dbl_mant_bits() < 32)
    385     return;
    386 
    387   for (nsize = 1; nsize <= numberof (np); nsize++)
    388     {
    389       refmpn_zero (np, nsize-1);
    390       np[nsize-1] = CNST_LIMB(0x81c25113);
    391       exp = - (nsize-1) * GMP_NUMB_BITS;
    392       got = mpn_get_d (np, nsize, (mp_size_t) 0, exp);
    393       if (got != want)
    394         {
    395           printf  ("mpn_get_d wrong on 2176995603 (0x81c25113)\n");
    396           printf  ("  nsize  %ld\n", (long) nsize);
    397           printf  ("  exp    %ld\n", exp);
    398           d_trace ("  got    ", got);
    399           d_trace ("  want   ", want);
    400           abort ();
    401         }
    402     }
    403 #endif
    404 }
    405 
    406 
    407 void
    408 check_rand (void)
    409 {
    410   gmp_randstate_ptr rands = RANDS;
    411   int            rep, i;
    412   unsigned long  mant_bits;
    413   long           exp, exp_min, exp_max;
    414   double         got, want, d;
    415   mp_size_t      nalloc, nsize, sign;
    416   mp_limb_t      nhigh_mask;
    417   mp_ptr         np;
    418 
    419   mant_bits = tests_dbl_mant_bits ();
    420   if (mant_bits == 0)
    421     return;
    422 
    423   /* Allow for vax D format with exponent 127 to -128 only.
    424      FIXME: Do something to probe for a valid exponent range.  */
    425   exp_min = -100 - mant_bits;
    426   exp_max =  100 - mant_bits;
    427 
    428   /* space for mant_bits */
    429   nalloc = BITS_TO_LIMBS (mant_bits);
    430   np = refmpn_malloc_limbs (nalloc);
    431   nhigh_mask = MP_LIMB_T_MAX
    432     >> (GMP_NAIL_BITS + nalloc * GMP_NUMB_BITS - mant_bits);
    433 
    434   for (rep = 0; rep < 200; rep++)
    435     {
    436       /* random exp_min to exp_max, inclusive */
    437       exp = exp_min + (long) gmp_urandomm_ui (rands, exp_max - exp_min + 1);
    438 
    439       /* mant_bits worth of random at np */
    440       if (rep & 1)
    441         mpn_random (np, nalloc);
    442       else
    443         mpn_random2 (np, nalloc);
    444       nsize = nalloc;
    445       np[nsize-1] &= nhigh_mask;
    446       MPN_NORMALIZE (np, nsize);
    447       if (nsize == 0)
    448         continue;
    449 
    450       sign = (mp_size_t) gmp_urandomb_ui (rands, 1L) - 1;
    451 
    452       /* want = {np,nsize}, converting one bit at a time */
    453       want = 0.0;
    454       for (i = 0, d = 1.0; i < mant_bits; i++, d *= 2.0)
    455         if (np[i/GMP_NUMB_BITS] & (CNST_LIMB(1) << (i%GMP_NUMB_BITS)))
    456           want += d;
    457       if (sign < 0)
    458         want = -want;
    459 
    460       /* want = want * 2^exp */
    461       for (i = 0; i < exp; i++)
    462         want *= 2.0;
    463       for (i = 0; i > exp; i--)
    464         want *= 0.5;
    465 
    466       got = mpn_get_d (np, nsize, sign, exp);
    467 
    468       if (got != want)
    469         {
    470           printf    ("mpn_get_d wrong on random data\n");
    471           printf    ("   sign     %ld\n", (long) sign);
    472           mpn_trace ("   n        ", np, nsize);
    473           printf    ("   nsize    %ld\n", (long) nsize);
    474           printf    ("   exp      %ld\n", exp);
    475           d_trace   ("   want     ", want);
    476           d_trace   ("   got      ", got);
    477           abort();
    478         }
    479     }
    480 
    481   free (np);
    482 }
    483 
    484 
    485 int
    486 main (void)
    487 {
    488   tests_start ();
    489   mp_trace_base = -16;
    490 
    491   check_onebit ();
    492   check_twobit ();
    493   check_inf ();
    494   check_underflow ();
    495   check_ieee_denorm ();
    496   check_ieee_overflow ();
    497   check_0x81c25113 ();
    498 #if ! (defined (__vax) || defined (__vax__))
    499   check_rand ();
    500 #endif
    501 
    502   tests_end ();
    503   exit (0);
    504 }
    505