Home | History | Annotate | Line # | Download | only in mpn
t-hgcd_appr.c revision 1.1
      1  1.1  mrg /* Test mpn_hgcd_appr.
      2  1.1  mrg 
      3  1.1  mrg Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2011 Free
      4  1.1  mrg Software Foundation, Inc.
      5  1.1  mrg 
      6  1.1  mrg This file is part of the GNU MP Library test suite.
      7  1.1  mrg 
      8  1.1  mrg The GNU MP Library test suite is free software; you can redistribute it
      9  1.1  mrg and/or modify it under the terms of the GNU General Public License as
     10  1.1  mrg published by the Free Software Foundation; either version 3 of the License,
     11  1.1  mrg or (at your option) any later version.
     12  1.1  mrg 
     13  1.1  mrg The GNU MP Library test suite is distributed in the hope that it will be
     14  1.1  mrg useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
     16  1.1  mrg Public License for more details.
     17  1.1  mrg 
     18  1.1  mrg You should have received a copy of the GNU General Public License along with
     19  1.1  mrg the GNU MP Library test suite.  If not, see http://www.gnu.org/licenses/.  */
     20  1.1  mrg 
     21  1.1  mrg #include <stdio.h>
     22  1.1  mrg #include <stdlib.h>
     23  1.1  mrg #include <string.h>
     24  1.1  mrg 
     25  1.1  mrg #include "gmp.h"
     26  1.1  mrg #include "gmp-impl.h"
     27  1.1  mrg #include "tests.h"
     28  1.1  mrg 
     29  1.1  mrg static mp_size_t one_test (mpz_t, mpz_t, int);
     30  1.1  mrg static void debug_mp (mpz_t, int);
     31  1.1  mrg 
     32  1.1  mrg #define MIN_OPERAND_SIZE 2
     33  1.1  mrg 
     34  1.1  mrg struct hgcd_ref
     35  1.1  mrg {
     36  1.1  mrg   mpz_t m[2][2];
     37  1.1  mrg };
     38  1.1  mrg 
     39  1.1  mrg static void hgcd_ref_init (struct hgcd_ref *hgcd);
     40  1.1  mrg static void hgcd_ref_clear (struct hgcd_ref *hgcd);
     41  1.1  mrg static int hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b);
     42  1.1  mrg static int hgcd_ref_equal (const struct hgcd_ref *, const struct hgcd_ref *);
     43  1.1  mrg static int hgcd_appr_valid_p (mpz_t, mpz_t, mp_size_t, struct hgcd_ref *,
     44  1.1  mrg 			      mpz_t, mpz_t, mp_size_t, struct hgcd_matrix *);
     45  1.1  mrg 
     46  1.1  mrg static int verbose_flag = 0;
     47  1.1  mrg 
     48  1.1  mrg int
     49  1.1  mrg main (int argc, char **argv)
     50  1.1  mrg {
     51  1.1  mrg   mpz_t op1, op2, temp1, temp2;
     52  1.1  mrg   int i, j, chain_len;
     53  1.1  mrg   gmp_randstate_ptr rands;
     54  1.1  mrg   mpz_t bs;
     55  1.1  mrg   unsigned long size_range;
     56  1.1  mrg 
     57  1.1  mrg   if (argc > 1)
     58  1.1  mrg     {
     59  1.1  mrg       if (strcmp (argv[1], "-v") == 0)
     60  1.1  mrg 	verbose_flag = 1;
     61  1.1  mrg       else
     62  1.1  mrg 	{
     63  1.1  mrg 	  fprintf (stderr, "Invalid argument.\n");
     64  1.1  mrg 	  return 1;
     65  1.1  mrg 	}
     66  1.1  mrg     }
     67  1.1  mrg 
     68  1.1  mrg   tests_start ();
     69  1.1  mrg   rands = RANDS;
     70  1.1  mrg 
     71  1.1  mrg   mpz_init (bs);
     72  1.1  mrg   mpz_init (op1);
     73  1.1  mrg   mpz_init (op2);
     74  1.1  mrg   mpz_init (temp1);
     75  1.1  mrg   mpz_init (temp2);
     76  1.1  mrg 
     77  1.1  mrg   for (i = 0; i < 15; i++)
     78  1.1  mrg     {
     79  1.1  mrg       /* Generate plain operands with unknown gcd.  These types of operands
     80  1.1  mrg 	 have proven to trigger certain bugs in development versions of the
     81  1.1  mrg 	 gcd code. */
     82  1.1  mrg 
     83  1.1  mrg       mpz_urandomb (bs, rands, 32);
     84  1.1  mrg       size_range = mpz_get_ui (bs) % 13 + 2;
     85  1.1  mrg 
     86  1.1  mrg       mpz_urandomb (bs, rands, size_range);
     87  1.1  mrg       mpz_urandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
     88  1.1  mrg       mpz_urandomb (bs, rands, size_range);
     89  1.1  mrg       mpz_urandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
     90  1.1  mrg 
     91  1.1  mrg       if (mpz_cmp (op1, op2) < 0)
     92  1.1  mrg 	mpz_swap (op1, op2);
     93  1.1  mrg 
     94  1.1  mrg       if (mpz_size (op1) > 0)
     95  1.1  mrg 	one_test (op1, op2, i);
     96  1.1  mrg 
     97  1.1  mrg       /* Generate a division chain backwards, allowing otherwise
     98  1.1  mrg 	 unlikely huge quotients.  */
     99  1.1  mrg 
    100  1.1  mrg       mpz_set_ui (op1, 0);
    101  1.1  mrg       mpz_urandomb (bs, rands, 32);
    102  1.1  mrg       mpz_urandomb (bs, rands, mpz_get_ui (bs) % 16 + 1);
    103  1.1  mrg       mpz_rrandomb (op2, rands, mpz_get_ui (bs));
    104  1.1  mrg       mpz_add_ui (op2, op2, 1);
    105  1.1  mrg 
    106  1.1  mrg #if 0
    107  1.1  mrg       chain_len = 1000000;
    108  1.1  mrg #else
    109  1.1  mrg       mpz_urandomb (bs, rands, 32);
    110  1.1  mrg       chain_len = mpz_get_ui (bs) % (GMP_NUMB_BITS * GCD_DC_THRESHOLD / 256);
    111  1.1  mrg #endif
    112  1.1  mrg 
    113  1.1  mrg       for (j = 0; j < chain_len; j++)
    114  1.1  mrg 	{
    115  1.1  mrg 	  mpz_urandomb (bs, rands, 32);
    116  1.1  mrg 	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
    117  1.1  mrg 	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
    118  1.1  mrg 	  mpz_add_ui (temp2, temp2, 1);
    119  1.1  mrg 	  mpz_mul (temp1, op2, temp2);
    120  1.1  mrg 	  mpz_add (op1, op1, temp1);
    121  1.1  mrg 
    122  1.1  mrg 	  /* Don't generate overly huge operands.  */
    123  1.1  mrg 	  if (SIZ (op1) > 3 * GCD_DC_THRESHOLD)
    124  1.1  mrg 	    break;
    125  1.1  mrg 
    126  1.1  mrg 	  mpz_urandomb (bs, rands, 32);
    127  1.1  mrg 	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
    128  1.1  mrg 	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
    129  1.1  mrg 	  mpz_add_ui (temp2, temp2, 1);
    130  1.1  mrg 	  mpz_mul (temp1, op1, temp2);
    131  1.1  mrg 	  mpz_add (op2, op2, temp1);
    132  1.1  mrg 
    133  1.1  mrg 	  /* Don't generate overly huge operands.  */
    134  1.1  mrg 	  if (SIZ (op2) > 3 * GCD_DC_THRESHOLD)
    135  1.1  mrg 	    break;
    136  1.1  mrg 	}
    137  1.1  mrg       if (mpz_cmp (op1, op2) < 0)
    138  1.1  mrg 	mpz_swap (op1, op2);
    139  1.1  mrg 
    140  1.1  mrg       if (mpz_size (op1) > 0)
    141  1.1  mrg 	one_test (op1, op2, i);
    142  1.1  mrg     }
    143  1.1  mrg 
    144  1.1  mrg   mpz_clear (bs);
    145  1.1  mrg   mpz_clear (op1);
    146  1.1  mrg   mpz_clear (op2);
    147  1.1  mrg   mpz_clear (temp1);
    148  1.1  mrg   mpz_clear (temp2);
    149  1.1  mrg 
    150  1.1  mrg   tests_end ();
    151  1.1  mrg   exit (0);
    152  1.1  mrg }
    153  1.1  mrg 
    154  1.1  mrg static void
    155  1.1  mrg debug_mp (mpz_t x, int base)
    156  1.1  mrg {
    157  1.1  mrg   mpz_out_str (stderr, base, x); fputc ('\n', stderr);
    158  1.1  mrg }
    159  1.1  mrg 
    160  1.1  mrg static int
    161  1.1  mrg mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize);
    162  1.1  mrg 
    163  1.1  mrg static mp_size_t
    164  1.1  mrg one_test (mpz_t a, mpz_t b, int i)
    165  1.1  mrg {
    166  1.1  mrg   struct hgcd_matrix hgcd;
    167  1.1  mrg   struct hgcd_ref ref;
    168  1.1  mrg 
    169  1.1  mrg   mpz_t ref_r0;
    170  1.1  mrg   mpz_t ref_r1;
    171  1.1  mrg   mpz_t hgcd_r0;
    172  1.1  mrg   mpz_t hgcd_r1;
    173  1.1  mrg 
    174  1.1  mrg   int res[2];
    175  1.1  mrg   mp_size_t asize;
    176  1.1  mrg   mp_size_t bsize;
    177  1.1  mrg 
    178  1.1  mrg   mp_size_t hgcd_init_scratch;
    179  1.1  mrg   mp_size_t hgcd_scratch;
    180  1.1  mrg 
    181  1.1  mrg   mp_ptr hgcd_init_tp;
    182  1.1  mrg   mp_ptr hgcd_tp;
    183  1.1  mrg   mp_limb_t marker[4];
    184  1.1  mrg 
    185  1.1  mrg   asize = a->_mp_size;
    186  1.1  mrg   bsize = b->_mp_size;
    187  1.1  mrg 
    188  1.1  mrg   ASSERT (asize >= bsize);
    189  1.1  mrg 
    190  1.1  mrg   hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize);
    191  1.1  mrg   hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch + 2) + 1;
    192  1.1  mrg   mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp);
    193  1.1  mrg 
    194  1.1  mrg   hgcd_scratch = mpn_hgcd_appr_itch (asize);
    195  1.1  mrg   hgcd_tp = refmpn_malloc_limbs (hgcd_scratch + 2) + 1;
    196  1.1  mrg 
    197  1.1  mrg   mpn_random (marker, 4);
    198  1.1  mrg 
    199  1.1  mrg   hgcd_init_tp[-1] = marker[0];
    200  1.1  mrg   hgcd_init_tp[hgcd_init_scratch] = marker[1];
    201  1.1  mrg   hgcd_tp[-1] = marker[2];
    202  1.1  mrg   hgcd_tp[hgcd_scratch] = marker[3];
    203  1.1  mrg 
    204  1.1  mrg #if 0
    205  1.1  mrg   fprintf (stderr,
    206  1.1  mrg 	   "one_test: i = %d asize = %d, bsize = %d\n",
    207  1.1  mrg 	   i, a->_mp_size, b->_mp_size);
    208  1.1  mrg 
    209  1.1  mrg   gmp_fprintf (stderr,
    210  1.1  mrg 	       "one_test: i = %d\n"
    211  1.1  mrg 	       "  a = %Zx\n"
    212  1.1  mrg 	       "  b = %Zx\n",
    213  1.1  mrg 	       i, a, b);
    214  1.1  mrg #endif
    215  1.1  mrg   hgcd_ref_init (&ref);
    216  1.1  mrg 
    217  1.1  mrg   mpz_init_set (ref_r0, a);
    218  1.1  mrg   mpz_init_set (ref_r1, b);
    219  1.1  mrg   res[0] = hgcd_ref (&ref, ref_r0, ref_r1);
    220  1.1  mrg 
    221  1.1  mrg   mpz_init_set (hgcd_r0, a);
    222  1.1  mrg   mpz_init_set (hgcd_r1, b);
    223  1.1  mrg   if (bsize < asize)
    224  1.1  mrg     {
    225  1.1  mrg       _mpz_realloc (hgcd_r1, asize);
    226  1.1  mrg       MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize);
    227  1.1  mrg     }
    228  1.1  mrg   res[1] = mpn_hgcd_appr (hgcd_r0->_mp_d,
    229  1.1  mrg 			  hgcd_r1->_mp_d,
    230  1.1  mrg 			  asize,
    231  1.1  mrg 			  &hgcd, hgcd_tp);
    232  1.1  mrg 
    233  1.1  mrg   if (hgcd_init_tp[-1] != marker[0]
    234  1.1  mrg       || hgcd_init_tp[hgcd_init_scratch] != marker[1]
    235  1.1  mrg       || hgcd_tp[-1] != marker[2]
    236  1.1  mrg       || hgcd_tp[hgcd_scratch] != marker[3])
    237  1.1  mrg     {
    238  1.1  mrg       fprintf (stderr, "ERROR in test %d\n", i);
    239  1.1  mrg       fprintf (stderr, "scratch space overwritten!\n");
    240  1.1  mrg 
    241  1.1  mrg       if (hgcd_init_tp[-1] != marker[0])
    242  1.1  mrg 	gmp_fprintf (stderr,
    243  1.1  mrg 		     "before init_tp: %Mx\n"
    244  1.1  mrg 		     "expected: %Mx\n",
    245  1.1  mrg 		     hgcd_init_tp[-1], marker[0]);
    246  1.1  mrg       if (hgcd_init_tp[hgcd_init_scratch] != marker[1])
    247  1.1  mrg 	gmp_fprintf (stderr,
    248  1.1  mrg 		     "after init_tp: %Mx\n"
    249  1.1  mrg 		     "expected: %Mx\n",
    250  1.1  mrg 		     hgcd_init_tp[hgcd_init_scratch], marker[1]);
    251  1.1  mrg       if (hgcd_tp[-1] != marker[2])
    252  1.1  mrg 	gmp_fprintf (stderr,
    253  1.1  mrg 		     "before tp: %Mx\n"
    254  1.1  mrg 		     "expected: %Mx\n",
    255  1.1  mrg 		     hgcd_tp[-1], marker[2]);
    256  1.1  mrg       if (hgcd_tp[hgcd_scratch] != marker[3])
    257  1.1  mrg 	gmp_fprintf (stderr,
    258  1.1  mrg 		     "after tp: %Mx\n"
    259  1.1  mrg 		     "expected: %Mx\n",
    260  1.1  mrg 		     hgcd_tp[hgcd_scratch], marker[3]);
    261  1.1  mrg 
    262  1.1  mrg       abort ();
    263  1.1  mrg     }
    264  1.1  mrg 
    265  1.1  mrg   if (!hgcd_appr_valid_p (a, b, res[0], &ref, ref_r0, ref_r1,
    266  1.1  mrg 			  res[1], &hgcd))
    267  1.1  mrg     {
    268  1.1  mrg       fprintf (stderr, "ERROR in test %d\n", i);
    269  1.1  mrg       fprintf (stderr, "Invalid results for hgcd and hgcd_ref\n");
    270  1.1  mrg       fprintf (stderr, "op1=");                 debug_mp (a, -16);
    271  1.1  mrg       fprintf (stderr, "op2=");                 debug_mp (b, -16);
    272  1.1  mrg       fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]);
    273  1.1  mrg       fprintf (stderr, "mpn_hgcd_appr: %ld\n", (long) res[1]);
    274  1.1  mrg       abort ();
    275  1.1  mrg     }
    276  1.1  mrg 
    277  1.1  mrg   refmpn_free_limbs (hgcd_init_tp - 1);
    278  1.1  mrg   refmpn_free_limbs (hgcd_tp - 1);
    279  1.1  mrg   hgcd_ref_clear (&ref);
    280  1.1  mrg   mpz_clear (ref_r0);
    281  1.1  mrg   mpz_clear (ref_r1);
    282  1.1  mrg   mpz_clear (hgcd_r0);
    283  1.1  mrg   mpz_clear (hgcd_r1);
    284  1.1  mrg 
    285  1.1  mrg   return res[0];
    286  1.1  mrg }
    287  1.1  mrg 
    288  1.1  mrg static void
    289  1.1  mrg hgcd_ref_init (struct hgcd_ref *hgcd)
    290  1.1  mrg {
    291  1.1  mrg   unsigned i;
    292  1.1  mrg   for (i = 0; i<2; i++)
    293  1.1  mrg     {
    294  1.1  mrg       unsigned j;
    295  1.1  mrg       for (j = 0; j<2; j++)
    296  1.1  mrg 	mpz_init (hgcd->m[i][j]);
    297  1.1  mrg     }
    298  1.1  mrg }
    299  1.1  mrg 
    300  1.1  mrg static void
    301  1.1  mrg hgcd_ref_clear (struct hgcd_ref *hgcd)
    302  1.1  mrg {
    303  1.1  mrg   unsigned i;
    304  1.1  mrg   for (i = 0; i<2; i++)
    305  1.1  mrg     {
    306  1.1  mrg       unsigned j;
    307  1.1  mrg       for (j = 0; j<2; j++)
    308  1.1  mrg 	mpz_clear (hgcd->m[i][j]);
    309  1.1  mrg     }
    310  1.1  mrg }
    311  1.1  mrg 
    312  1.1  mrg static int
    313  1.1  mrg sdiv_qr (mpz_t q, mpz_t r, mp_size_t s, const mpz_t a, const mpz_t b)
    314  1.1  mrg {
    315  1.1  mrg   mpz_fdiv_qr (q, r, a, b);
    316  1.1  mrg   if (mpz_size (r) <= s)
    317  1.1  mrg     {
    318  1.1  mrg       mpz_add (r, r, b);
    319  1.1  mrg       mpz_sub_ui (q, q, 1);
    320  1.1  mrg     }
    321  1.1  mrg 
    322  1.1  mrg   return (mpz_sgn (q) > 0);
    323  1.1  mrg }
    324  1.1  mrg 
    325  1.1  mrg static int
    326  1.1  mrg hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b)
    327  1.1  mrg {
    328  1.1  mrg   mp_size_t n = MAX (mpz_size (a), mpz_size (b));
    329  1.1  mrg   mp_size_t s = n/2 + 1;
    330  1.1  mrg   mpz_t q;
    331  1.1  mrg   int res;
    332  1.1  mrg 
    333  1.1  mrg   if (mpz_size (a) <= s || mpz_size (b) <= s)
    334  1.1  mrg     return 0;
    335  1.1  mrg 
    336  1.1  mrg   res = mpz_cmp (a, b);
    337  1.1  mrg   if (res < 0)
    338  1.1  mrg     {
    339  1.1  mrg       mpz_sub (b, b, a);
    340  1.1  mrg       if (mpz_size (b) <= s)
    341  1.1  mrg 	return 0;
    342  1.1  mrg 
    343  1.1  mrg       mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 0);
    344  1.1  mrg       mpz_set_ui (hgcd->m[1][0], 1); mpz_set_ui (hgcd->m[1][1], 1);
    345  1.1  mrg     }
    346  1.1  mrg   else if (res > 0)
    347  1.1  mrg     {
    348  1.1  mrg       mpz_sub (a, a, b);
    349  1.1  mrg       if (mpz_size (a) <= s)
    350  1.1  mrg 	return 0;
    351  1.1  mrg 
    352  1.1  mrg       mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 1);
    353  1.1  mrg       mpz_set_ui (hgcd->m[1][0], 0); mpz_set_ui (hgcd->m[1][1], 1);
    354  1.1  mrg     }
    355  1.1  mrg   else
    356  1.1  mrg     return 0;
    357  1.1  mrg 
    358  1.1  mrg   mpz_init (q);
    359  1.1  mrg 
    360  1.1  mrg   for (;;)
    361  1.1  mrg     {
    362  1.1  mrg       ASSERT (mpz_size (a) > s);
    363  1.1  mrg       ASSERT (mpz_size (b) > s);
    364  1.1  mrg 
    365  1.1  mrg       if (mpz_cmp (a, b) > 0)
    366  1.1  mrg 	{
    367  1.1  mrg 	  if (!sdiv_qr (q, a, s, a, b))
    368  1.1  mrg 	    break;
    369  1.1  mrg 	  mpz_addmul (hgcd->m[0][1], q, hgcd->m[0][0]);
    370  1.1  mrg 	  mpz_addmul (hgcd->m[1][1], q, hgcd->m[1][0]);
    371  1.1  mrg 	}
    372  1.1  mrg       else
    373  1.1  mrg 	{
    374  1.1  mrg 	  if (!sdiv_qr (q, b, s, b, a))
    375  1.1  mrg 	    break;
    376  1.1  mrg 	  mpz_addmul (hgcd->m[0][0], q, hgcd->m[0][1]);
    377  1.1  mrg 	  mpz_addmul (hgcd->m[1][0], q, hgcd->m[1][1]);
    378  1.1  mrg 	}
    379  1.1  mrg     }
    380  1.1  mrg 
    381  1.1  mrg   mpz_clear (q);
    382  1.1  mrg 
    383  1.1  mrg   return 1;
    384  1.1  mrg }
    385  1.1  mrg 
    386  1.1  mrg static int
    387  1.1  mrg mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize)
    388  1.1  mrg {
    389  1.1  mrg   mp_srcptr ap = a->_mp_d;
    390  1.1  mrg   mp_size_t asize = a->_mp_size;
    391  1.1  mrg 
    392  1.1  mrg   MPN_NORMALIZE (bp, bsize);
    393  1.1  mrg   return asize == bsize && mpn_cmp (ap, bp, asize) == 0;
    394  1.1  mrg }
    395  1.1  mrg 
    396  1.1  mrg static int
    397  1.1  mrg hgcd_ref_equal (const struct hgcd_ref *A, const struct hgcd_ref *B)
    398  1.1  mrg {
    399  1.1  mrg   unsigned i;
    400  1.1  mrg 
    401  1.1  mrg   for (i = 0; i<2; i++)
    402  1.1  mrg     {
    403  1.1  mrg       unsigned j;
    404  1.1  mrg 
    405  1.1  mrg       for (j = 0; j<2; j++)
    406  1.1  mrg 	if (mpz_cmp (A->m[i][j], B->m[i][j]) != 0)
    407  1.1  mrg 	  return 0;
    408  1.1  mrg     }
    409  1.1  mrg 
    410  1.1  mrg   return 1;
    411  1.1  mrg }
    412  1.1  mrg 
    413  1.1  mrg static int
    414  1.1  mrg hgcd_appr_valid_p (mpz_t a, mpz_t b, mp_size_t res0,
    415  1.1  mrg 		   struct hgcd_ref *ref, mpz_t ref_r0, mpz_t ref_r1,
    416  1.1  mrg 		   mp_size_t res1, struct hgcd_matrix *hgcd)
    417  1.1  mrg {
    418  1.1  mrg   mp_size_t n = MAX (mpz_size (a), mpz_size (b));
    419  1.1  mrg   mp_size_t s = n/2 + 1;
    420  1.1  mrg 
    421  1.1  mrg   mp_bitcnt_t dbits, abits, margin;
    422  1.1  mrg   mpz_t appr_r0, appr_r1, t, q;
    423  1.1  mrg   struct hgcd_ref appr;
    424  1.1  mrg 
    425  1.1  mrg   if (!res0)
    426  1.1  mrg     {
    427  1.1  mrg       if (!res1)
    428  1.1  mrg 	return 1;
    429  1.1  mrg 
    430  1.1  mrg       fprintf (stderr, "mpn_hgcd_appr returned 1 when no reduction possible.\n");
    431  1.1  mrg       return 0;
    432  1.1  mrg     }
    433  1.1  mrg 
    434  1.1  mrg   /* NOTE: No *_clear calls on error return, since we're going to
    435  1.1  mrg      abort anyway. */
    436  1.1  mrg   mpz_init (t);
    437  1.1  mrg   mpz_init (q);
    438  1.1  mrg   hgcd_ref_init (&appr);
    439  1.1  mrg   mpz_init (appr_r0);
    440  1.1  mrg   mpz_init (appr_r1);
    441  1.1  mrg 
    442  1.1  mrg   if (mpz_size (ref_r0) <= s)
    443  1.1  mrg     {
    444  1.1  mrg       fprintf (stderr, "ref_r0 too small!!!: "); debug_mp (ref_r0, 16);
    445  1.1  mrg       return 0;
    446  1.1  mrg     }
    447  1.1  mrg   if (mpz_size (ref_r1) <= s)
    448  1.1  mrg     {
    449  1.1  mrg       fprintf (stderr, "ref_r1 too small!!!: "); debug_mp (ref_r1, 16);
    450  1.1  mrg       return 0;
    451  1.1  mrg     }
    452  1.1  mrg 
    453  1.1  mrg   mpz_sub (t, ref_r0, ref_r1);
    454  1.1  mrg   dbits = mpz_sizeinbase (t, 2);
    455  1.1  mrg   if (dbits > s*GMP_NUMB_BITS)
    456  1.1  mrg     {
    457  1.1  mrg       fprintf (stderr, "ref |r0 - r1| too large!!!: "); debug_mp (t, 16);
    458  1.1  mrg       return 0;
    459  1.1  mrg     }
    460  1.1  mrg 
    461  1.1  mrg   if (!res1)
    462  1.1  mrg     {
    463  1.1  mrg       mpz_set (appr_r0, a);
    464  1.1  mrg       mpz_set (appr_r1, b);
    465  1.1  mrg     }
    466  1.1  mrg   else
    467  1.1  mrg     {
    468  1.1  mrg       unsigned i;
    469  1.1  mrg 
    470  1.1  mrg       for (i = 0; i<2; i++)
    471  1.1  mrg 	{
    472  1.1  mrg 	  unsigned j;
    473  1.1  mrg 
    474  1.1  mrg 	  for (j = 0; j<2; j++)
    475  1.1  mrg 	    {
    476  1.1  mrg 	      mp_size_t mn = hgcd->n;
    477  1.1  mrg 	      MPN_NORMALIZE (hgcd->p[i][j], mn);
    478  1.1  mrg 	      mpz_realloc (appr.m[i][j], mn);
    479  1.1  mrg 	      MPN_COPY (PTR (appr.m[i][j]), hgcd->p[i][j], mn);
    480  1.1  mrg 	      SIZ (appr.m[i][j]) = mn;
    481  1.1  mrg 	    }
    482  1.1  mrg 	}
    483  1.1  mrg       mpz_mul (appr_r0, appr.m[1][1], a);
    484  1.1  mrg       mpz_mul (t, appr.m[0][1], b);
    485  1.1  mrg       mpz_sub (appr_r0, appr_r0, t);
    486  1.1  mrg       if (mpz_sgn (appr_r0) <= 0
    487  1.1  mrg 	  || mpz_size (appr_r0) <= s)
    488  1.1  mrg 	{
    489  1.1  mrg 	  fprintf (stderr, "appr_r0 too small: "); debug_mp (appr_r0, 16);
    490  1.1  mrg 	  return 0;
    491  1.1  mrg 	}
    492  1.1  mrg 
    493  1.1  mrg       mpz_mul (appr_r1, appr.m[1][0], a);
    494  1.1  mrg       mpz_mul (t, appr.m[0][0], b);
    495  1.1  mrg       mpz_sub (appr_r1, t, appr_r1);
    496  1.1  mrg       if (mpz_sgn (appr_r1) <= 0
    497  1.1  mrg 	  || mpz_size (appr_r1) <= s)
    498  1.1  mrg 	{
    499  1.1  mrg 	  fprintf (stderr, "appr_r1 too small: "); debug_mp (appr_r1, 16);
    500  1.1  mrg 	  return 0;
    501  1.1  mrg 	}
    502  1.1  mrg     }
    503  1.1  mrg 
    504  1.1  mrg   mpz_sub (t, appr_r0, appr_r1);
    505  1.1  mrg   abits = mpz_sizeinbase (t, 2);
    506  1.1  mrg   if (abits < dbits)
    507  1.1  mrg     {
    508  1.1  mrg       fprintf (stderr, "|r0 - r1| too small: "); debug_mp (t, 16);
    509  1.1  mrg       return 0;
    510  1.1  mrg     }
    511  1.1  mrg 
    512  1.1  mrg   /* We lose one bit each time we discard the least significant limbs.
    513  1.1  mrg      For the lehmer code, that can happen at most s * (GMP_NUMB_BITS)
    514  1.1  mrg      / (GMP_NUMB_BITS - 1) times. For the dc code, we lose an entire
    515  1.1  mrg      limb (or more?) for each level of recursion. */
    516  1.1  mrg 
    517  1.1  mrg   margin = (n/2+1) * GMP_NUMB_BITS / (GMP_NUMB_BITS - 1);
    518  1.1  mrg   {
    519  1.1  mrg     mp_size_t rn;
    520  1.1  mrg     for (rn = n; ABOVE_THRESHOLD (rn, HGCD_APPR_THRESHOLD); rn = (rn + 1)/2)
    521  1.1  mrg       margin += GMP_NUMB_BITS;
    522  1.1  mrg   }
    523  1.1  mrg 
    524  1.1  mrg   if (verbose_flag && abits > dbits)
    525  1.1  mrg     fprintf (stderr, "n = %u: sbits = %u: ref #(r0-r1): %u, appr #(r0-r1): %u excess: %d, margin: %u\n",
    526  1.1  mrg 	     (unsigned) n, (unsigned) s*GMP_NUMB_BITS,
    527  1.1  mrg 	     (unsigned) dbits, (unsigned) abits,
    528  1.1  mrg 	     (int) abits - s * GMP_NUMB_BITS, (unsigned) margin);
    529  1.1  mrg 
    530  1.1  mrg   if (abits > s*GMP_NUMB_BITS + margin)
    531  1.1  mrg     {
    532  1.1  mrg       fprintf (stderr, "appr |r0 - r1| much larger than minimal (by %u bits, margin = %u bits)\n",
    533  1.1  mrg 	       (unsigned) (abits - s*GMP_NUMB_BITS), (unsigned) margin);
    534  1.1  mrg       return 0;
    535  1.1  mrg     }
    536  1.1  mrg 
    537  1.1  mrg   while (mpz_cmp (appr_r0, ref_r0) > 0 || mpz_cmp (appr_r1, ref_r1) > 0)
    538  1.1  mrg     {
    539  1.1  mrg       ASSERT (mpz_size (appr_r0) > s);
    540  1.1  mrg       ASSERT (mpz_size (appr_r1) > s);
    541  1.1  mrg 
    542  1.1  mrg       if (mpz_cmp (appr_r0, appr_r1) > 0)
    543  1.1  mrg 	{
    544  1.1  mrg 	  if (!sdiv_qr (q, appr_r0, s, appr_r0, appr_r1))
    545  1.1  mrg 	    break;
    546  1.1  mrg 	  mpz_addmul (appr.m[0][1], q, appr.m[0][0]);
    547  1.1  mrg 	  mpz_addmul (appr.m[1][1], q, appr.m[1][0]);
    548  1.1  mrg 	}
    549  1.1  mrg       else
    550  1.1  mrg 	{
    551  1.1  mrg 	  if (!sdiv_qr (q, appr_r1, s, appr_r1, appr_r0))
    552  1.1  mrg 	    break;
    553  1.1  mrg 	  mpz_addmul (appr.m[0][0], q, appr.m[0][1]);
    554  1.1  mrg 	  mpz_addmul (appr.m[1][0], q, appr.m[1][1]);
    555  1.1  mrg 	}
    556  1.1  mrg     }
    557  1.1  mrg 
    558  1.1  mrg   if (mpz_cmp (appr_r0, ref_r0) != 0
    559  1.1  mrg       || mpz_cmp (appr_r1, ref_r1) != 0
    560  1.1  mrg       || !hgcd_ref_equal (ref, &appr))
    561  1.1  mrg     {
    562  1.1  mrg       fprintf (stderr, "appr_r0: "); debug_mp (appr_r0, 16);
    563  1.1  mrg       fprintf (stderr, "ref_r0: "); debug_mp (ref_r0, 16);
    564  1.1  mrg 
    565  1.1  mrg       fprintf (stderr, "appr_r1: "); debug_mp (appr_r1, 16);
    566  1.1  mrg       fprintf (stderr, "ref_r1: "); debug_mp (ref_r1, 16);
    567  1.1  mrg 
    568  1.1  mrg       return 0;
    569  1.1  mrg     }
    570  1.1  mrg   mpz_clear (t);
    571  1.1  mrg   mpz_clear (q);
    572  1.1  mrg   hgcd_ref_clear (&appr);
    573  1.1  mrg   mpz_clear (appr_r0);
    574  1.1  mrg   mpz_clear (appr_r1);
    575  1.1  mrg 
    576  1.1  mrg   return 1;
    577  1.1  mrg }
    578