github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/tests/mpz/t-gcd.c (about)

     1  /* Test mpz_gcd, mpz_gcdext, and mpz_gcd_ui.
     2  
     3  Copyright 1991, 1993, 1994, 1996, 1997, 2000-2005, 2008, 2009, 2012 Free
     4  Software Foundation, Inc.
     5  
     6  This file is part of the GNU MP Library test suite.
     7  
     8  The GNU MP Library test suite is free software; you can redistribute it
     9  and/or modify it under the terms of the GNU General Public License as
    10  published by the Free Software Foundation; either version 3 of the License,
    11  or (at your option) any later version.
    12  
    13  The GNU MP Library test suite is distributed in the hope that it will be
    14  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
    16  Public License for more details.
    17  
    18  You should have received a copy of the GNU General Public License along with
    19  the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
    20  
    21  #include <stdio.h>
    22  #include <stdlib.h>
    23  
    24  #include "gmp.h"
    25  #include "gmp-impl.h"
    26  #include "tests.h"
    27  
    28  void one_test (mpz_t, mpz_t, mpz_t, int);
    29  void debug_mp (mpz_t, int);
    30  
    31  static int gcdext_valid_p (const mpz_t, const mpz_t, const mpz_t, const mpz_t);
    32  
    33  /* Keep one_test's variables global, so that we don't need
    34     to reinitialize them for each test.  */
    35  mpz_t gcd1, gcd2, s, temp1, temp2, temp3;
    36  
    37  #define MAX_SCHOENHAGE_THRESHOLD HGCD_REDUCE_THRESHOLD
    38  
    39  /* Define this to make all operands be large enough for Schoenhage gcd
    40     to be used.  */
    41  #ifndef WHACK_SCHOENHAGE
    42  #define WHACK_SCHOENHAGE 0
    43  #endif
    44  
    45  #if WHACK_SCHOENHAGE
    46  #define MIN_OPERAND_BITSIZE (MAX_SCHOENHAGE_THRESHOLD * GMP_NUMB_BITS)
    47  #else
    48  #define MIN_OPERAND_BITSIZE 1
    49  #endif
    50  
    51  
    52  void
    53  check_data (void)
    54  {
    55    static const struct {
    56      const char *a;
    57      const char *b;
    58      const char *want;
    59    } data[] = {
    60      /* This tickled a bug in gmp 4.1.2 mpn/x86/k6/gcd_finda.asm. */
    61      { "0x3FFC000007FFFFFFFFFF00000000003F83FFFFFFFFFFFFFFF80000000000000001",
    62        "0x1FFE0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000000000000000000000001",
    63        "5" }
    64    };
    65  
    66    mpz_t  a, b, got, want;
    67    int    i;
    68  
    69    mpz_inits (a, b, got, want, NULL);
    70  
    71    for (i = 0; i < numberof (data); i++)
    72      {
    73        mpz_set_str_or_abort (a, data[i].a, 0);
    74        mpz_set_str_or_abort (b, data[i].b, 0);
    75        mpz_set_str_or_abort (want, data[i].want, 0);
    76        mpz_gcd (got, a, b);
    77        MPZ_CHECK_FORMAT (got);
    78        if (mpz_cmp (got, want) != 0)
    79  	{
    80  	  printf    ("mpz_gcd wrong on data[%d]\n", i);
    81  	  printf    (" a  %s\n", data[i].a);
    82  	  printf    (" b  %s\n", data[i].b);
    83  	  mpz_trace (" a", a);
    84  	  mpz_trace (" b", b);
    85  	  mpz_trace (" want", want);
    86  	  mpz_trace (" got ", got);
    87  	  abort ();
    88  	}
    89      }
    90  
    91    mpz_clears (a, b, got, want, NULL);
    92  }
    93  
    94  void
    95  make_chain_operands (mpz_t ref, mpz_t a, mpz_t b, gmp_randstate_t rs, int nb1, int nb2, int chain_len)
    96  {
    97    mpz_t bs, temp1, temp2;
    98    int j;
    99  
   100    mpz_inits (bs, temp1, temp2, NULL);
   101  
   102    /* Generate a division chain backwards, allowing otherwise unlikely huge
   103       quotients.  */
   104  
   105    mpz_set_ui (a, 0);
   106    mpz_urandomb (bs, rs, 32);
   107    mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb1 + 1);
   108    mpz_rrandomb (b, rs, mpz_get_ui (bs));
   109    mpz_add_ui (b, b, 1);
   110    mpz_set (ref, b);
   111  
   112    for (j = 0; j < chain_len; j++)
   113      {
   114        mpz_urandomb (bs, rs, 32);
   115        mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb2 + 1);
   116        mpz_rrandomb (temp2, rs, mpz_get_ui (bs) + 1);
   117        mpz_add_ui (temp2, temp2, 1);
   118        mpz_mul (temp1, b, temp2);
   119        mpz_add (a, a, temp1);
   120  
   121        mpz_urandomb (bs, rs, 32);
   122        mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb2 + 1);
   123        mpz_rrandomb (temp2, rs, mpz_get_ui (bs) + 1);
   124        mpz_add_ui (temp2, temp2, 1);
   125        mpz_mul (temp1, a, temp2);
   126        mpz_add (b, b, temp1);
   127      }
   128  
   129    mpz_clears (bs, temp1, temp2, NULL);
   130  }
   131  
   132  /* Test operands from a table of seed data.  This variant creates the operands
   133     using plain ol' mpz_rrandomb.  This is a hack for better coverage of the gcd
   134     code, which depends on that the random number generators give the exact
   135     numbers we expect.  */
   136  void
   137  check_kolmo1 (void)
   138  {
   139    static const struct {
   140      unsigned int seed;
   141      int nb;
   142      const char *want;
   143    } data[] = {
   144      { 59618, 38208, "5"},
   145      { 76521, 49024, "3"},
   146      { 85869, 54976, "1"},
   147      { 99449, 63680, "1"},
   148      {112453, 72000, "1"}
   149    };
   150  
   151    gmp_randstate_t rs;
   152    mpz_t  bs, a, b, want;
   153    int    i, unb, vnb, nb;
   154  
   155    gmp_randinit_default (rs);
   156  
   157    mpz_inits (bs, a, b, want, NULL);
   158  
   159    for (i = 0; i < numberof (data); i++)
   160      {
   161        nb = data[i].nb;
   162  
   163        gmp_randseed_ui (rs, data[i].seed);
   164  
   165        mpz_urandomb (bs, rs, 32);
   166        unb = mpz_get_ui (bs) % nb;
   167        mpz_urandomb (bs, rs, 32);
   168        vnb = mpz_get_ui (bs) % nb;
   169  
   170        mpz_rrandomb (a, rs, unb);
   171        mpz_rrandomb (b, rs, vnb);
   172  
   173        mpz_set_str_or_abort (want, data[i].want, 0);
   174  
   175        one_test (a, b, want, -1);
   176      }
   177  
   178    mpz_clears (bs, a, b, want, NULL);
   179    gmp_randclear (rs);
   180  }
   181  
   182  /* Test operands from a table of seed data.  This variant creates the operands
   183     using a division chain.  This is a hack for better coverage of the gcd
   184     code, which depends on that the random number generators give the exact
   185     numbers we expect.  */
   186  void
   187  check_kolmo2 (void)
   188  {
   189    static const struct {
   190      unsigned int seed;
   191      int nb, chain_len;
   192    } data[] = {
   193      {  917, 15, 5 },
   194      { 1032, 18, 6 },
   195      { 1167, 18, 6 },
   196      { 1174, 18, 6 },
   197      { 1192, 18, 6 },
   198    };
   199  
   200    gmp_randstate_t rs;
   201    mpz_t  bs, a, b, want;
   202    int    i;
   203  
   204    gmp_randinit_default (rs);
   205  
   206    mpz_inits (bs, a, b, want, NULL);
   207  
   208    for (i = 0; i < numberof (data); i++)
   209      {
   210        gmp_randseed_ui (rs, data[i].seed);
   211        make_chain_operands (want, a, b, rs, data[i].nb, data[i].nb, data[i].chain_len);
   212        one_test (a, b, want, -1);
   213      }
   214  
   215    mpz_clears (bs, a, b, want, NULL);
   216    gmp_randclear (rs);
   217  }
   218  
   219  int
   220  main (int argc, char **argv)
   221  {
   222    mpz_t op1, op2, ref;
   223    int i, chain_len;
   224    gmp_randstate_ptr rands;
   225    mpz_t bs;
   226    unsigned long bsi, size_range;
   227    long int reps = 200;
   228  
   229    tests_start ();
   230    TESTS_REPS (reps, argv, argc);
   231  
   232    rands = RANDS;
   233  
   234    mpz_inits (bs, op1, op2, ref, gcd1, gcd2, temp1, temp2, temp3, s, NULL);
   235  
   236    check_data ();
   237    check_kolmo1 ();
   238    check_kolmo2 ();
   239  
   240    /* Testcase to exercise the u0 == u1 case in mpn_gcdext_lehmer_n. */
   241    mpz_set_ui (op2, GMP_NUMB_MAX); /* FIXME: Huge limb doesn't always fit */
   242    mpz_mul_2exp (op1, op2, 100);
   243    mpz_add (op1, op1, op2);
   244    mpz_mul_ui (op2, op2, 2);
   245    one_test (op1, op2, NULL, -1);
   246  
   247    for (i = 0; i < reps; i++)
   248      {
   249        /* Generate plain operands with unknown gcd.  These types of operands
   250  	 have proven to trigger certain bugs in development versions of the
   251  	 gcd code.  The "hgcd->row[3].rsize > M" ASSERT is not triggered by
   252  	 the division chain code below, but that is most likely just a result
   253  	 of that other ASSERTs are triggered before it.  */
   254  
   255        mpz_urandomb (bs, rands, 32);
   256        size_range = mpz_get_ui (bs) % 17 + 2;
   257  
   258        mpz_urandomb (bs, rands, size_range);
   259        mpz_rrandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_BITSIZE);
   260        mpz_urandomb (bs, rands, size_range);
   261        mpz_rrandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_BITSIZE);
   262  
   263        mpz_urandomb (bs, rands, 8);
   264        bsi = mpz_get_ui (bs);
   265  
   266        if ((bsi & 0x3c) == 4)
   267  	mpz_mul (op1, op1, op2);	/* make op1 a multiple of op2 */
   268        else if ((bsi & 0x3c) == 8)
   269  	mpz_mul (op2, op1, op2);	/* make op2 a multiple of op1 */
   270  
   271        if ((bsi & 1) != 0)
   272  	mpz_neg (op1, op1);
   273        if ((bsi & 2) != 0)
   274  	mpz_neg (op2, op2);
   275  
   276        one_test (op1, op2, NULL, i);
   277  
   278        /* Generate a division chain backwards, allowing otherwise unlikely huge
   279  	 quotients.  */
   280  
   281        mpz_urandomb (bs, rands, 32);
   282        chain_len = mpz_get_ui (bs) % LOG2C (GMP_NUMB_BITS * MAX_SCHOENHAGE_THRESHOLD);
   283        mpz_urandomb (bs, rands, 32);
   284        chain_len = mpz_get_ui (bs) % (1 << chain_len) / 32;
   285  
   286        make_chain_operands (ref, op1, op2, rands, 16, 12, chain_len);
   287  
   288        one_test (op1, op2, ref, i);
   289      }
   290  
   291    mpz_clears (bs, op1, op2, ref, gcd1, gcd2, temp1, temp2, temp3, s, NULL);
   292  
   293    tests_end ();
   294    exit (0);
   295  }
   296  
   297  void
   298  debug_mp (mpz_t x, int base)
   299  {
   300    mpz_out_str (stderr, base, x); fputc ('\n', stderr);
   301  }
   302  
   303  void
   304  one_test (mpz_t op1, mpz_t op2, mpz_t ref, int i)
   305  {
   306    /*
   307    printf ("%d %d %d\n", SIZ (op1), SIZ (op2), ref != NULL ? SIZ (ref) : 0);
   308    fflush (stdout);
   309    */
   310  
   311    /*
   312    fprintf (stderr, "op1=");  debug_mp (op1, -16);
   313    fprintf (stderr, "op2=");  debug_mp (op2, -16);
   314    */
   315  
   316    mpz_gcdext (gcd1, s, NULL, op1, op2);
   317    MPZ_CHECK_FORMAT (gcd1);
   318    MPZ_CHECK_FORMAT (s);
   319  
   320    if (ref && mpz_cmp (ref, gcd1) != 0)
   321      {
   322        fprintf (stderr, "ERROR in test %d\n", i);
   323        fprintf (stderr, "mpz_gcdext returned incorrect result\n");
   324        fprintf (stderr, "op1=");                 debug_mp (op1, -16);
   325        fprintf (stderr, "op2=");                 debug_mp (op2, -16);
   326        fprintf (stderr, "expected result:\n");   debug_mp (ref, -16);
   327        fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd1, -16);
   328        abort ();
   329      }
   330  
   331    if (!gcdext_valid_p(op1, op2, gcd1, s))
   332      {
   333        fprintf (stderr, "ERROR in test %d\n", i);
   334        fprintf (stderr, "mpz_gcdext returned invalid result\n");
   335        fprintf (stderr, "op1=");                 debug_mp (op1, -16);
   336        fprintf (stderr, "op2=");                 debug_mp (op2, -16);
   337        fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd1, -16);
   338        fprintf (stderr, "s=");                   debug_mp (s, -16);
   339        abort ();
   340      }
   341  
   342    mpz_gcd (gcd2, op1, op2);
   343    MPZ_CHECK_FORMAT (gcd2);
   344  
   345    if (mpz_cmp (gcd2, gcd1) != 0)
   346      {
   347        fprintf (stderr, "ERROR in test %d\n", i);
   348        fprintf (stderr, "mpz_gcd returned incorrect result\n");
   349        fprintf (stderr, "op1=");                 debug_mp (op1, -16);
   350        fprintf (stderr, "op2=");                 debug_mp (op2, -16);
   351        fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
   352        fprintf (stderr, "mpz_gcd returns:\n");   debug_mp (gcd2, -16);
   353        abort ();
   354      }
   355  
   356    /* This should probably move to t-gcd_ui.c */
   357    if (mpz_fits_ulong_p (op1) || mpz_fits_ulong_p (op2))
   358      {
   359        if (mpz_fits_ulong_p (op1))
   360  	mpz_gcd_ui (gcd2, op2, mpz_get_ui (op1));
   361        else
   362  	mpz_gcd_ui (gcd2, op1, mpz_get_ui (op2));
   363        if (mpz_cmp (gcd2, gcd1))
   364  	{
   365  	  fprintf (stderr, "ERROR in test %d\n", i);
   366  	  fprintf (stderr, "mpz_gcd_ui returned incorrect result\n");
   367  	  fprintf (stderr, "op1=");                 debug_mp (op1, -16);
   368  	  fprintf (stderr, "op2=");                 debug_mp (op2, -16);
   369  	  fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
   370  	  fprintf (stderr, "mpz_gcd_ui returns:\n");   debug_mp (gcd2, -16);
   371  	  abort ();
   372  	}
   373      }
   374  
   375    mpz_gcdext (gcd2, temp1, temp2, op1, op2);
   376    MPZ_CHECK_FORMAT (gcd2);
   377    MPZ_CHECK_FORMAT (temp1);
   378    MPZ_CHECK_FORMAT (temp2);
   379  
   380    mpz_mul (temp1, temp1, op1);
   381    mpz_mul (temp2, temp2, op2);
   382    mpz_add (temp1, temp1, temp2);
   383  
   384    if (mpz_cmp (gcd1, gcd2) != 0
   385        || mpz_cmp (gcd2, temp1) != 0)
   386      {
   387        fprintf (stderr, "ERROR in test %d\n", i);
   388        fprintf (stderr, "mpz_gcdext returned incorrect result\n");
   389        fprintf (stderr, "op1=");                 debug_mp (op1, -16);
   390        fprintf (stderr, "op2=");                 debug_mp (op2, -16);
   391        fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
   392        fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd2, -16);
   393        abort ();
   394      }
   395  }
   396  
   397  /* Called when g is supposed to be gcd(a,b), and g = s a + t b, for some t.
   398     Uses temp1, temp2 and temp3. */
   399  static int
   400  gcdext_valid_p (const mpz_t a, const mpz_t b, const mpz_t g, const mpz_t s)
   401  {
   402    /* It's not clear that gcd(0,0) is well defined, but we allow it and require that
   403       gcd(0,0) = 0. */
   404    if (mpz_sgn (g) < 0)
   405      return 0;
   406  
   407    if (mpz_sgn (a) == 0)
   408      {
   409        /* Must have g == abs (b). Any value for s is in some sense "correct",
   410  	 but it makes sense to require that s == 0. */
   411        return mpz_cmpabs (g, b) == 0 && mpz_sgn (s) == 0;
   412      }
   413    else if (mpz_sgn (b) == 0)
   414      {
   415        /* Must have g == abs (a), s == sign (a) */
   416        return mpz_cmpabs (g, a) == 0 && mpz_cmp_si (s, mpz_sgn (a)) == 0;
   417      }
   418  
   419    if (mpz_sgn (g) <= 0)
   420      return 0;
   421  
   422    mpz_tdiv_qr (temp1, temp3, a, g);
   423    if (mpz_sgn (temp3) != 0)
   424      return 0;
   425  
   426    mpz_tdiv_qr (temp2, temp3, b, g);
   427    if (mpz_sgn (temp3) != 0)
   428      return 0;
   429  
   430    /* Require that 2 |s| < |b/g|, or |s| == 1. */
   431    if (mpz_cmpabs_ui (s, 1) > 0)
   432      {
   433        mpz_mul_2exp (temp3, s, 1);
   434        if (mpz_cmpabs (temp3, temp2) >= 0)
   435  	return 0;
   436      }
   437  
   438    /* Compute the other cofactor. */
   439    mpz_mul(temp2, s, a);
   440    mpz_sub(temp2, g, temp2);
   441    mpz_tdiv_qr(temp2, temp3, temp2, b);
   442  
   443    if (mpz_sgn (temp3) != 0)
   444      return 0;
   445  
   446    /* Require that 2 |t| < |a/g| or |t| == 1*/
   447    if (mpz_cmpabs_ui (temp2, 1) > 0)
   448      {
   449        mpz_mul_2exp (temp2, temp2, 1);
   450        if (mpz_cmpabs (temp2, temp1) >= 0)
   451  	return 0;
   452      }
   453    return 1;
   454  }