Home | History | Annotate | Line # | Download | only in mpz
      1 /* Exercise mpz_bin_ui and mpz_bin_uiui.
      2 
      3 Copyright 2000, 2001, 2010, 2012, 2018 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 https://www.gnu.org/licenses/.  */
     19 
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include "gmp-impl.h"
     23 #include "tests.h"
     24 
     25 /* Default number of generated tests. */
     26 #define COUNT 700
     27 
     28 void
     29 try_mpz_bin_ui (mpz_srcptr want, mpz_srcptr n, unsigned long k)
     30 {
     31   mpz_t  got;
     32 
     33   mpz_init (got);
     34   mpz_bin_ui (got, n, k);
     35   MPZ_CHECK_FORMAT (got);
     36   if (mpz_cmp (got, want) != 0)
     37     {
     38       printf ("mpz_bin_ui wrong\n");
     39       printf ("  n="); mpz_out_str (stdout, 10, n); printf ("\n");
     40       printf ("  k=%lu\n", k);
     41       printf ("  got="); mpz_out_str (stdout, 10, got); printf ("\n");
     42       printf ("  want="); mpz_out_str (stdout, 10, want); printf ("\n");
     43       abort();
     44     }
     45   mpz_clear (got);
     46 }
     47 
     48 
     49 void
     50 try_mpz_bin_uiui (mpz_srcptr want, unsigned long n, unsigned long k)
     51 {
     52   mpz_t  got;
     53 
     54   mpz_init (got);
     55   mpz_bin_uiui (got, n, k);
     56   MPZ_CHECK_FORMAT (got);
     57   if (mpz_cmp (got, want) != 0)
     58     {
     59       printf ("mpz_bin_uiui wrong\n");
     60       printf ("  n=%lu\n", n);
     61       printf ("  k=%lu\n", k);
     62       printf ("  got="); mpz_out_str (stdout, 10, got); printf ("\n");
     63       printf ("  want="); mpz_out_str (stdout, 10, want); printf ("\n");
     64       abort();
     65     }
     66   mpz_clear (got);
     67 }
     68 
     69 
     70 void
     71 samples (void)
     72 {
     73   static const struct {
     74     const char     *n;
     75     unsigned long  k;
     76     const char     *want;
     77   } data[] = {
     78 
     79     {   "0", 123456, "0" },
     80     {   "1", 543210, "0" },
     81     {   "2", 123321, "0" },
     82     {   "3", 234567, "0" },
     83     {   "10", 23456, "0" },
     84 
     85     /* negatives, using bin(-n,k)=bin(n+k-1,k) */
     86     {   "-1",  0,  "1"  },
     87     {   "-1",  1, "-1"  },
     88     {   "-1",  2,  "1"  },
     89     {   "-1",  3, "-1"  },
     90     {   "-1",  4,  "1"  },
     91 
     92     {   "-2",  0,  "1"  },
     93     {   "-2",  1, "-2"  },
     94     {   "-2",  2,  "3"  },
     95     {   "-2",  3, "-4"  },
     96     {   "-2",  4,  "5"  },
     97     {   "-2",  5, "-6"  },
     98     {   "-2",  6,  "7"  },
     99 
    100     {   "-3",  0,   "1"  },
    101     {   "-3",  1,  "-3"  },
    102     {   "-3",  2,   "6"  },
    103     {   "-3",  3, "-10"  },
    104     {   "-3",  4,  "15"  },
    105     {   "-3",  5, "-21"  },
    106     {   "-3",  6,  "28"  },
    107 
    108     /* A few random values */
    109     {   "41", 20,  "269128937220" },
    110     {   "62", 37,  "147405545359541742" },
    111     {   "50", 18,  "18053528883775" },
    112     {  "149", 21,  "19332950844468483467894649" },
    113   };
    114 
    115   mpz_t  n, want;
    116   int    i;
    117 
    118   mpz_init (n);
    119   mpz_init (want);
    120 
    121   for (i = 0; i < numberof (data); i++)
    122     {
    123       mpz_set_str_or_abort (n, data[i].n, 0);
    124       mpz_set_str_or_abort (want, data[i].want, 0);
    125 
    126       try_mpz_bin_ui (want, n, data[i].k);
    127 
    128       if (mpz_fits_ulong_p (n))
    129 	try_mpz_bin_uiui (want, mpz_get_ui (n), data[i].k);
    130     }
    131 
    132   mpz_clear (n);
    133   mpz_clear (want);
    134 }
    135 
    136 
    137 /* Test some bin(2k,k) cases.  This produces some biggish numbers to
    138    exercise the limb accumulating code.  */
    139 void
    140 twos (int count)
    141 {
    142   mpz_t          n, want;
    143   unsigned long  k;
    144 
    145   mpz_init (n);
    146 
    147   mpz_init_set_ui (want, (unsigned long) 2);
    148   for (k = 1; k < count; k++)
    149     {
    150       mpz_set_ui (n, 2*k);
    151       try_mpz_bin_ui (want, n, k);
    152 
    153       try_mpz_bin_uiui (want, 2*k, k);
    154 
    155       mpz_mul_ui (want, want, 2*(2*k+1));
    156       mpz_fdiv_q_ui (want, want, k+1);
    157     }
    158 
    159   mpz_clear (n);
    160   mpz_clear (want);
    161 }
    162 
    163 /* Test some random bin(n,k) cases.  This produces some biggish
    164    numbers to exercise the limb accumulating code.  */
    165 void
    166 randomwalk (int count)
    167 {
    168   mpz_t          n_z, want, tmp;
    169   unsigned long  n, k, i, r;
    170   int            tests;
    171   gmp_randstate_ptr rands;
    172 
    173   rands = RANDS;
    174   mpz_init (n_z);
    175 
    176   k = 3;
    177   n = 12;
    178   mpz_init_set_ui (want, (unsigned long) 220); /* binomial(12,3) = 220 */
    179 
    180   for (tests = 1; tests < count; tests++)
    181     {
    182       r = gmp_urandomm_ui (rands, 62) + 1;
    183       for (i = r & 7; i > 0; i--)
    184 	{
    185 	  n++; k++;
    186 	  mpz_mul_ui (want, want, n);
    187 	  mpz_fdiv_q_ui (want, want, k);
    188 	}
    189       for (i = r >> 3; i > 0; i--)
    190 	{
    191 	  n++;
    192 	  mpz_mul_ui (want, want, n);
    193 	  mpz_fdiv_q_ui (want, want, n - k);
    194 	}
    195 
    196       mpz_set_ui (n_z, n);
    197       try_mpz_bin_ui (want, n_z, k);
    198 
    199       try_mpz_bin_uiui (want, n, k);
    200     }
    201 
    202   k = 2;
    203   mpz_urandomb (n_z, rands, 200);
    204   mpz_mul (want, n_z, n_z); /* want = n_z ^ 2 */
    205   mpz_sub (want, want, n_z); /* want = n_z ^ 2 - n_z = n_z (n_z- 1) */
    206   mpz_tdiv_q_2exp (want, want, 1); /* want = n_z (n_z- 1) / 2 = binomial (n_z, 2) */
    207   mpz_init (tmp);
    208   for (tests = 1; tests < count; tests++)
    209     {
    210       r = gmp_urandomm_ui (rands, 62) + 1;
    211       for (i = r & 7; i > 0; i--)
    212 	{
    213 	  k++;
    214 	  mpz_add_ui (n_z, n_z, 1);
    215 	  mpz_mul (want, want, n_z);
    216 	  mpz_tdiv_q_ui (want, want, k);
    217 	}
    218       for (i = r >> 3; i > 0; i--)
    219 	{
    220 	  mpz_add_ui (n_z, n_z, 1);
    221 	  mpz_mul (want, want, n_z);
    222 	  mpz_sub_ui (tmp, n_z, k);
    223 	  mpz_tdiv_q (want, want, tmp);
    224 	}
    225 
    226       try_mpz_bin_ui (want, n_z, k);
    227     }
    228 
    229   mpz_clear (tmp);
    230   mpz_clear (n_z);
    231   mpz_clear (want);
    232 }
    233 
    234 /* Test some random bin(n,k) cases.  This produces some biggish
    235    numbers to exercise the limb accumulating code.  */
    236 void
    237 randomwalk_down (int count)
    238 {
    239   mpz_t          n_z, want, tmp;
    240   unsigned long  n, k, i, r;
    241   int            tests;
    242   gmp_randstate_ptr rands;
    243 
    244   rands = RANDS;
    245   mpz_init (n_z);
    246   mpz_init (tmp);
    247 
    248   k = 2;
    249   n = ULONG_MAX;
    250   mpz_init_set_ui (want, n);
    251   mpz_mul_ui (want, want, n >> 1);
    252 
    253   for (tests = 1; tests < count; tests++)
    254     {
    255       r = gmp_urandomm_ui (rands, 62) + 1;
    256       for (i = r & 7; i > 0; i--)
    257 	{
    258 	  mpz_mul_ui (want, want, n - k);
    259 	  ++k;
    260 	  mpz_tdiv_q_ui (want, want, k);
    261 	}
    262       for (i = r >> 3; i > 0; i--)
    263 	{
    264 	  mpz_mul_ui (want, want, n - k);
    265 	  mpz_tdiv_q_ui (want, want, n);
    266 	  --n;
    267 	}
    268 
    269       mpz_set_ui (n_z, n);
    270       try_mpz_bin_ui (want, n_z, n - k);
    271 
    272       try_mpz_bin_uiui (want, n, n - k);
    273     }
    274 
    275   mpz_clear (tmp);
    276   mpz_clear (n_z);
    277   mpz_clear (want);
    278 }
    279 
    280 
    281 /* Test all bin(n,k) cases, with 0 <= k <= n + 1 <= count.  */
    282 void
    283 smallexaustive (unsigned int count)
    284 {
    285   mpz_t          n_z, want;
    286   unsigned long  n, k;
    287 
    288   mpz_init (n_z);
    289   mpz_init (want);
    290 
    291   for (n = 0; n < count; n++)
    292     {
    293       mpz_set_ui (want, (unsigned long) 1);
    294       mpz_set_ui (n_z, n);
    295       for (k = 0; k <= n; k++)
    296 	{
    297 	  try_mpz_bin_ui (want, n_z, k);
    298 	  try_mpz_bin_uiui (want, n, k);
    299 	  mpz_mul_ui (want, want, n - k);
    300 	  mpz_fdiv_q_ui (want, want, k + 1);
    301 	}
    302       try_mpz_bin_ui (want, n_z, k);
    303       try_mpz_bin_uiui (want, n, k);
    304     }
    305 
    306   mpz_clear (n_z);
    307   mpz_clear (want);
    308 }
    309 
    310 int
    311 main (int argc, char **argv)
    312 {
    313   int count;
    314 
    315   count = COUNT;
    316   TESTS_REPS (count, argv, argc);
    317 
    318   tests_start ();
    319 
    320   samples ();
    321   smallexaustive (count >> 4);
    322   twos (count >> 1);
    323   randomwalk (count - (count >> 1));
    324   randomwalk_down (count >> 1);
    325 
    326   tests_end ();
    327   exit (0);
    328 }
    329