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

     1  /* Test mpn_hgcd.
     2  
     3  Copyright 1991, 1993, 1994, 1996, 1997, 2000-2004 Free Software Foundation,
     4  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  static mp_size_t one_test (mpz_t, mpz_t, int);
    29  static void debug_mp (mpz_t, int);
    30  
    31  #define MIN_OPERAND_SIZE 2
    32  
    33  /* Fixed values, for regression testing of mpn_hgcd. */
    34  struct value { int res; const char *a; const char *b; };
    35  static const struct value hgcd_values[] = {
    36  #if GMP_NUMB_BITS == 32
    37    { 5,
    38      "0x1bddff867272a9296ac493c251d7f46f09a5591fe",
    39      "0xb55930a2a68a916450a7de006031068c5ddb0e5c" },
    40    { 4,
    41      "0x2f0ece5b1ee9c15e132a01d55768dc13",
    42      "0x1c6f4fd9873cdb24466e6d03e1cc66e7" },
    43    { 3, "0x7FFFFC003FFFFFFFFFC5", "0x3FFFFE001FFFFFFFFFE3"},
    44  #endif
    45    { -1, NULL, NULL }
    46  };
    47  
    48  struct hgcd_ref
    49  {
    50    mpz_t m[2][2];
    51  };
    52  
    53  static void hgcd_ref_init (struct hgcd_ref *);
    54  static void hgcd_ref_clear (struct hgcd_ref *);
    55  static int hgcd_ref (struct hgcd_ref *, mpz_t, mpz_t);
    56  static int hgcd_ref_equal (const struct hgcd_matrix *, const struct hgcd_ref *);
    57  
    58  int
    59  main (int argc, char **argv)
    60  {
    61    mpz_t op1, op2, temp1, temp2;
    62    int i, j, chain_len;
    63    gmp_randstate_ptr rands;
    64    mpz_t bs;
    65    unsigned long size_range;
    66  
    67    tests_start ();
    68    rands = RANDS;
    69  
    70    mpz_init (bs);
    71    mpz_init (op1);
    72    mpz_init (op2);
    73    mpz_init (temp1);
    74    mpz_init (temp2);
    75  
    76    for (i = 0; hgcd_values[i].res >= 0; i++)
    77      {
    78        mp_size_t res;
    79  
    80        mpz_set_str (op1, hgcd_values[i].a, 0);
    81        mpz_set_str (op2, hgcd_values[i].b, 0);
    82  
    83        res = one_test (op1, op2, -1-i);
    84        if (res != hgcd_values[i].res)
    85  	{
    86  	  fprintf (stderr, "ERROR in test %d\n", -1-i);
    87  	  fprintf (stderr, "Bad return code from hgcd\n");
    88  	  fprintf (stderr, "op1=");                 debug_mp (op1, -16);
    89  	  fprintf (stderr, "op2=");                 debug_mp (op2, -16);
    90  	  fprintf (stderr, "expected: %d\n", hgcd_values[i].res);
    91  	  fprintf (stderr, "hgcd:     %d\n", (int) res);
    92  	  abort ();
    93  	}
    94      }
    95  
    96    for (i = 0; i < 15; i++)
    97      {
    98        /* Generate plain operands with unknown gcd.  These types of operands
    99  	 have proven to trigger certain bugs in development versions of the
   100  	 gcd code. */
   101  
   102        mpz_urandomb (bs, rands, 32);
   103        size_range = mpz_get_ui (bs) % 13 + 2;
   104  
   105        mpz_urandomb (bs, rands, size_range);
   106        mpz_rrandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
   107        mpz_urandomb (bs, rands, size_range);
   108        mpz_rrandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
   109  
   110        if (mpz_cmp (op1, op2) < 0)
   111  	mpz_swap (op1, op2);
   112  
   113        if (mpz_size (op1) > 0)
   114  	one_test (op1, op2, i);
   115  
   116        /* Generate a division chain backwards, allowing otherwise
   117  	 unlikely huge quotients.  */
   118  
   119        mpz_set_ui (op1, 0);
   120        mpz_urandomb (bs, rands, 32);
   121        mpz_urandomb (bs, rands, mpz_get_ui (bs) % 16 + 1);
   122        mpz_rrandomb (op2, rands, mpz_get_ui (bs));
   123        mpz_add_ui (op2, op2, 1);
   124  
   125  #if 0
   126        chain_len = 1000000;
   127  #else
   128        mpz_urandomb (bs, rands, 32);
   129        chain_len = mpz_get_ui (bs) % (GMP_NUMB_BITS * GCD_DC_THRESHOLD / 256);
   130  #endif
   131  
   132        for (j = 0; j < chain_len; j++)
   133  	{
   134  	  mpz_urandomb (bs, rands, 32);
   135  	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
   136  	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
   137  	  mpz_add_ui (temp2, temp2, 1);
   138  	  mpz_mul (temp1, op2, temp2);
   139  	  mpz_add (op1, op1, temp1);
   140  
   141  	  /* Don't generate overly huge operands.  */
   142  	  if (SIZ (op1) > 3 * GCD_DC_THRESHOLD)
   143  	    break;
   144  
   145  	  mpz_urandomb (bs, rands, 32);
   146  	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
   147  	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
   148  	  mpz_add_ui (temp2, temp2, 1);
   149  	  mpz_mul (temp1, op1, temp2);
   150  	  mpz_add (op2, op2, temp1);
   151  
   152  	  /* Don't generate overly huge operands.  */
   153  	  if (SIZ (op2) > 3 * GCD_DC_THRESHOLD)
   154  	    break;
   155  	}
   156        if (mpz_cmp (op1, op2) < 0)
   157  	mpz_swap (op1, op2);
   158  
   159        if (mpz_size (op1) > 0)
   160  	one_test (op1, op2, i);
   161      }
   162  
   163    mpz_clear (bs);
   164    mpz_clear (op1);
   165    mpz_clear (op2);
   166    mpz_clear (temp1);
   167    mpz_clear (temp2);
   168  
   169    tests_end ();
   170    exit (0);
   171  }
   172  
   173  static void
   174  debug_mp (mpz_t x, int base)
   175  {
   176    mpz_out_str (stderr, base, x); fputc ('\n', stderr);
   177  }
   178  
   179  static int
   180  mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize);
   181  
   182  static mp_size_t
   183  one_test (mpz_t a, mpz_t b, int i)
   184  {
   185    struct hgcd_matrix hgcd;
   186    struct hgcd_ref ref;
   187  
   188    mpz_t ref_r0;
   189    mpz_t ref_r1;
   190    mpz_t hgcd_r0;
   191    mpz_t hgcd_r1;
   192  
   193    mp_size_t res[2];
   194    mp_size_t asize;
   195    mp_size_t bsize;
   196  
   197    mp_size_t hgcd_init_scratch;
   198    mp_size_t hgcd_scratch;
   199  
   200    mp_ptr hgcd_init_tp;
   201    mp_ptr hgcd_tp;
   202  
   203    asize = a->_mp_size;
   204    bsize = b->_mp_size;
   205  
   206    ASSERT (asize >= bsize);
   207  
   208    hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize);
   209    hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch);
   210    mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp);
   211  
   212    hgcd_scratch = mpn_hgcd_itch (asize);
   213    hgcd_tp = refmpn_malloc_limbs (hgcd_scratch);
   214  
   215  #if 0
   216    fprintf (stderr,
   217  	   "one_test: i = %d asize = %d, bsize = %d\n",
   218  	   i, a->_mp_size, b->_mp_size);
   219  
   220    gmp_fprintf (stderr,
   221  	       "one_test: i = %d\n"
   222  	       "  a = %Zx\n"
   223  	       "  b = %Zx\n",
   224  	       i, a, b);
   225  #endif
   226    hgcd_ref_init (&ref);
   227  
   228    mpz_init_set (ref_r0, a);
   229    mpz_init_set (ref_r1, b);
   230    res[0] = hgcd_ref (&ref, ref_r0, ref_r1);
   231  
   232    mpz_init_set (hgcd_r0, a);
   233    mpz_init_set (hgcd_r1, b);
   234    if (bsize < asize)
   235      {
   236        _mpz_realloc (hgcd_r1, asize);
   237        MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize);
   238      }
   239    res[1] = mpn_hgcd (hgcd_r0->_mp_d,
   240  		     hgcd_r1->_mp_d,
   241  		     asize,
   242  		     &hgcd, hgcd_tp);
   243  
   244    if (res[0] != res[1])
   245      {
   246        fprintf (stderr, "ERROR in test %d\n", i);
   247        fprintf (stderr, "Different return value from hgcd and hgcd_ref\n");
   248        fprintf (stderr, "op1=");                 debug_mp (a, -16);
   249        fprintf (stderr, "op2=");                 debug_mp (b, -16);
   250        fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]);
   251        fprintf (stderr, "mpn_hgcd: %ld\n", (long) res[1]);
   252        abort ();
   253      }
   254    if (res[0] > 0)
   255      {
   256        if (!hgcd_ref_equal (&hgcd, &ref)
   257  	  || !mpz_mpn_equal (ref_r0, hgcd_r0->_mp_d, res[1])
   258  	  || !mpz_mpn_equal (ref_r1, hgcd_r1->_mp_d, res[1]))
   259  	{
   260  	  fprintf (stderr, "ERROR in test %d\n", i);
   261  	  fprintf (stderr, "mpn_hgcd and hgcd_ref returned different values\n");
   262  	  fprintf (stderr, "op1=");                 debug_mp (a, -16);
   263  	  fprintf (stderr, "op2=");                 debug_mp (b, -16);
   264  	  abort ();
   265  	}
   266      }
   267  
   268    refmpn_free_limbs (hgcd_init_tp);
   269    refmpn_free_limbs (hgcd_tp);
   270    hgcd_ref_clear (&ref);
   271    mpz_clear (ref_r0);
   272    mpz_clear (ref_r1);
   273    mpz_clear (hgcd_r0);
   274    mpz_clear (hgcd_r1);
   275  
   276    return res[0];
   277  }
   278  
   279  static void
   280  hgcd_ref_init (struct hgcd_ref *hgcd)
   281  {
   282    unsigned i;
   283    for (i = 0; i<2; i++)
   284      {
   285        unsigned j;
   286        for (j = 0; j<2; j++)
   287  	mpz_init (hgcd->m[i][j]);
   288      }
   289  }
   290  
   291  static void
   292  hgcd_ref_clear (struct hgcd_ref *hgcd)
   293  {
   294    unsigned i;
   295    for (i = 0; i<2; i++)
   296      {
   297        unsigned j;
   298        for (j = 0; j<2; j++)
   299  	mpz_clear (hgcd->m[i][j]);
   300      }
   301  }
   302  
   303  
   304  static int
   305  sdiv_qr (mpz_t q, mpz_t r, mp_size_t s, const mpz_t a, const mpz_t b)
   306  {
   307    mpz_fdiv_qr (q, r, a, b);
   308    if (mpz_size (r) <= s)
   309      {
   310        mpz_add (r, r, b);
   311        mpz_sub_ui (q, q, 1);
   312      }
   313  
   314    return (mpz_sgn (q) > 0);
   315  }
   316  
   317  static int
   318  hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b)
   319  {
   320    mp_size_t n = MAX (mpz_size (a), mpz_size (b));
   321    mp_size_t s = n/2 + 1;
   322    mp_size_t asize;
   323    mp_size_t bsize;
   324    mpz_t q;
   325    int res;
   326  
   327    if (mpz_size (a) <= s || mpz_size (b) <= s)
   328      return 0;
   329  
   330    res = mpz_cmp (a, b);
   331    if (res < 0)
   332      {
   333        mpz_sub (b, b, a);
   334        if (mpz_size (b) <= s)
   335  	return 0;
   336  
   337        mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 0);
   338        mpz_set_ui (hgcd->m[1][0], 1); mpz_set_ui (hgcd->m[1][1], 1);
   339      }
   340    else if (res > 0)
   341      {
   342        mpz_sub (a, a, b);
   343        if (mpz_size (a) <= s)
   344  	return 0;
   345  
   346        mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 1);
   347        mpz_set_ui (hgcd->m[1][0], 0); mpz_set_ui (hgcd->m[1][1], 1);
   348      }
   349    else
   350      return 0;
   351  
   352    mpz_init (q);
   353  
   354    for (;;)
   355      {
   356        ASSERT (mpz_size (a) > s);
   357        ASSERT (mpz_size (b) > s);
   358  
   359        if (mpz_cmp (a, b) > 0)
   360  	{
   361  	  if (!sdiv_qr (q, a, s, a, b))
   362  	    break;
   363  	  mpz_addmul (hgcd->m[0][1], q, hgcd->m[0][0]);
   364  	  mpz_addmul (hgcd->m[1][1], q, hgcd->m[1][0]);
   365  	}
   366        else
   367  	{
   368  	  if (!sdiv_qr (q, b, s, b, a))
   369  	    break;
   370  	  mpz_addmul (hgcd->m[0][0], q, hgcd->m[0][1]);
   371  	  mpz_addmul (hgcd->m[1][0], q, hgcd->m[1][1]);
   372  	}
   373      }
   374  
   375    mpz_clear (q);
   376  
   377    asize = mpz_size (a);
   378    bsize = mpz_size (b);
   379    return MAX (asize, bsize);
   380  }
   381  
   382  static int
   383  mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize)
   384  {
   385    mp_srcptr ap = a->_mp_d;
   386    mp_size_t asize = a->_mp_size;
   387  
   388    MPN_NORMALIZE (bp, bsize);
   389    return asize == bsize && mpn_cmp (ap, bp, asize) == 0;
   390  }
   391  
   392  static int
   393  hgcd_ref_equal (const struct hgcd_matrix *hgcd, const struct hgcd_ref *ref)
   394  {
   395    unsigned i;
   396  
   397    for (i = 0; i<2; i++)
   398      {
   399        unsigned j;
   400  
   401        for (j = 0; j<2; j++)
   402  	if (!mpz_mpn_equal (ref->m[i][j], hgcd->p[i][j], hgcd->n))
   403  	  return 0;
   404      }
   405  
   406    return 1;
   407  }