~ubuntu-branches/ubuntu/vivid/gcl/vivid

« back to all changes in this revision

Viewing changes to gmp/mpn/generic/gcdext.c

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2002-03-04 14:29:59 UTC
  • Revision ID: james.westby@ubuntu.com-20020304142959-dey14w08kr7lldu3
Tags: upstream-2.5.0.cvs20020219
ImportĀ upstreamĀ versionĀ 2.5.0.cvs20020219

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* mpn_gcdext -- Extended Greatest Common Divisor.
 
2
 
 
3
Copyright (C) 1996, 1998, 2000 Free Software Foundation, Inc.
 
4
 
 
5
This file is part of the GNU MP Library.
 
6
 
 
7
The GNU MP Library is free software; you can redistribute it and/or modify
 
8
it under the terms of the GNU Lesser General Public License as published by
 
9
the Free Software Foundation; either version 2.1 of the License, or (at your
 
10
option) any later version.
 
11
 
 
12
The GNU MP Library is distributed in the hope that it will be useful, but
 
13
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
14
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
15
License for more details.
 
16
 
 
17
You should have received a copy of the GNU Lesser General Public License
 
18
along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
 
19
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 
20
MA 02111-1307, USA. */
 
21
 
 
22
#include <stdlib.h>
 
23
#include "gmp.h"
 
24
#include "gmp-impl.h"
 
25
#include "longlong.h"
 
26
 
 
27
#ifndef GCDEXT_THRESHOLD
 
28
#define GCDEXT_THRESHOLD 17
 
29
#endif
 
30
 
 
31
#ifndef EXTEND
 
32
#define EXTEND 1
 
33
#endif
 
34
 
 
35
#if STAT
 
36
int arr[BITS_PER_MP_LIMB];
 
37
#endif
 
38
 
 
39
 
 
40
/* mpn_gcdext (GP, SP, SSIZE, UP, USIZE, VP, VSIZE)
 
41
 
 
42
   Compute the extended GCD of {UP,USIZE} and {VP,VSIZE} and store the
 
43
   greatest common divisor at GP (unless it is 0), and the first cofactor at
 
44
   SP.  Write the size of the cofactor through the pointer SSIZE.  Return the
 
45
   size of the value at GP.  Note that SP might be a negative number; this is
 
46
   denoted by storing the negative of the size through SSIZE.
 
47
 
 
48
   {UP,USIZE} and {VP,VSIZE} are both clobbered.
 
49
 
 
50
   The space allocation for all four areas needs to be USIZE+1.
 
51
 
 
52
   Preconditions: 1) U >= V.
 
53
                  2) V > 0.  */
 
54
 
 
55
/* We use Lehmer's algorithm.  The idea is to extract the most significant
 
56
   bits of the operands, and compute the continued fraction for them.  We then
 
57
   apply the gathered cofactors to the full operands.
 
58
 
 
59
   Idea 1: After we have performed a full division, don't shift operands back,
 
60
           but instead account for the extra factors-of-2 thus introduced.
 
61
   Idea 2: Simple generalization to use divide-and-conquer would give us an
 
62
           algorithm that runs faster than O(n^2).
 
63
   Idea 3: The input numbers need less space as the computation progresses,
 
64
           while the s0 and s1 variables need more space.  To save memory, we
 
65
           could make them share space, and have the latter variables grow
 
66
           into the former.
 
67
   Idea 4: We should not do double-limb arithmetic from the start.  Instead,
 
68
           do things in single-limb arithmetic until the quotients differ,
 
69
           and then switch to double-limb arithmetic.  */
 
70
 
 
71
 
 
72
/* Division optimized for small quotients.  If the quotient is more than one limb,
 
73
   store 1 in *qh and return 0.  */
 
74
static mp_limb_t
 
75
#if __STDC__
 
76
div2 (mp_limb_t *qh, mp_limb_t n1, mp_limb_t n0, mp_limb_t d1, mp_limb_t d0)
 
77
#else
 
78
div2 (qh, n1, n0, d1, d0)
 
79
     mp_limb_t *qh;
 
80
     mp_limb_t n1;
 
81
     mp_limb_t n0;
 
82
     mp_limb_t d1;
 
83
     mp_limb_t d0;
 
84
#endif
 
85
{
 
86
  if (d1 == 0)
 
87
    {
 
88
      *qh = 1;
 
89
      return 0;
 
90
    }
 
91
 
 
92
  if ((mp_limb_signed_t) n1 < 0)
 
93
    {
 
94
      mp_limb_t q;
 
95
      int cnt;
 
96
      for (cnt = 1; (mp_limb_signed_t) d1 >= 0; cnt++)
 
97
        {
 
98
          d1 = (d1 << 1) | (d0 >> (BITS_PER_MP_LIMB - 1));
 
99
          d0 = d0 << 1;
 
100
        }
 
101
 
 
102
      q = 0;
 
103
      while (cnt)
 
104
        {
 
105
          q <<= 1;
 
106
          if (n1 > d1 || (n1 == d1 && n0 >= d0))
 
107
            {
 
108
              sub_ddmmss (n1, n0, n1, n0, d1, d0);
 
109
              q |= 1;
 
110
            }
 
111
          d0 = (d1 << (BITS_PER_MP_LIMB - 1)) | (d0 >> 1);
 
112
          d1 = d1 >> 1;
 
113
          cnt--;
 
114
        }
 
115
 
 
116
      *qh = 0;
 
117
      return q;
 
118
    }
 
119
  else
 
120
    {
 
121
      mp_limb_t q;
 
122
      int cnt;
 
123
      for (cnt = 0; n1 > d1 || (n1 == d1 && n0 >= d0); cnt++)
 
124
        {
 
125
          d1 = (d1 << 1) | (d0 >> (BITS_PER_MP_LIMB - 1));
 
126
          d0 = d0 << 1;
 
127
        }
 
128
 
 
129
      q = 0;
 
130
      while (cnt)
 
131
        {
 
132
          d0 = (d1 << (BITS_PER_MP_LIMB - 1)) | (d0 >> 1);
 
133
          d1 = d1 >> 1;
 
134
          q <<= 1;
 
135
          if (n1 > d1 || (n1 == d1 && n0 >= d0))
 
136
            {
 
137
              sub_ddmmss (n1, n0, n1, n0, d1, d0);
 
138
              q |= 1;
 
139
            }
 
140
          cnt--;
 
141
        }
 
142
 
 
143
      *qh = 0;
 
144
      return q;
 
145
    }
 
146
}
 
147
 
 
148
mp_size_t
 
149
#if EXTEND
 
150
#if __STDC__
 
151
mpn_gcdext (mp_ptr gp, mp_ptr s0p, mp_size_t *s0size,
 
152
            mp_ptr up, mp_size_t size, mp_ptr vp, mp_size_t vsize)
 
153
#else
 
154
mpn_gcdext (gp, s0p, s0size, up, size, vp, vsize)
 
155
     mp_ptr gp;
 
156
     mp_ptr s0p;
 
157
     mp_size_t *s0size;
 
158
     mp_ptr up;
 
159
     mp_size_t size;
 
160
     mp_ptr vp;
 
161
     mp_size_t vsize;
 
162
#endif
 
163
#else
 
164
#if __STDC__
 
165
mpn_gcd (mp_ptr gp,
 
166
         mp_ptr up, mp_size_t size, mp_ptr vp, mp_size_t vsize)
 
167
#else
 
168
mpn_gcd (gp, up, size, vp, vsize)
 
169
     mp_ptr gp;
 
170
     mp_ptr up;
 
171
     mp_size_t size;
 
172
     mp_ptr vp;
 
173
     mp_size_t vsize;
 
174
#endif
 
175
#endif
 
176
{
 
177
  mp_limb_t A, B, C, D;
 
178
  int cnt;
 
179
  mp_ptr tp, wp;
 
180
#if RECORD
 
181
  mp_limb_t max = 0;
 
182
#endif
 
183
#if EXTEND
 
184
  mp_ptr s1p;
 
185
  mp_ptr orig_s0p = s0p;
 
186
  mp_size_t ssize;
 
187
  int sign = 1;
 
188
#endif
 
189
  int use_double_flag;
 
190
  TMP_DECL (mark);
 
191
 
 
192
  TMP_MARK (mark);
 
193
 
 
194
  use_double_flag = (size >= GCDEXT_THRESHOLD);
 
195
 
 
196
  tp = (mp_ptr) TMP_ALLOC ((size + 1) * BYTES_PER_MP_LIMB);
 
197
  wp = (mp_ptr) TMP_ALLOC ((size + 1) * BYTES_PER_MP_LIMB);
 
198
#if EXTEND
 
199
  s1p = (mp_ptr) TMP_ALLOC ((size + 1) * BYTES_PER_MP_LIMB);
 
200
 
 
201
  MPN_ZERO (s0p, size);
 
202
  MPN_ZERO (s1p, size);
 
203
 
 
204
  s0p[0] = 1;
 
205
  s1p[0] = 0;
 
206
  ssize = 1;
 
207
#endif
 
208
 
 
209
  if (size > vsize)
 
210
    {
 
211
      /* Normalize V (and shift up U the same amount).  */
 
212
      count_leading_zeros (cnt, vp[vsize - 1]);
 
213
      if (cnt != 0)
 
214
        {
 
215
          mp_limb_t cy;
 
216
          mpn_lshift (vp, vp, vsize, cnt);
 
217
          cy = mpn_lshift (up, up, size, cnt);
 
218
          up[size] = cy;
 
219
          size += cy != 0;
 
220
        }
 
221
 
 
222
      mpn_divmod (up + vsize, up, size, vp, vsize);
 
223
#if EXTEND
 
224
      /* This is really what it boils down to in this case... */
 
225
      s0p[0] = 0;
 
226
      s1p[0] = 1;
 
227
      sign = -sign;
 
228
#endif
 
229
      size = vsize;
 
230
      if (cnt != 0)
 
231
        {
 
232
          mpn_rshift (up, up, size, cnt);
 
233
          mpn_rshift (vp, vp, size, cnt);
 
234
        }
 
235
      MP_PTR_SWAP (up, vp);
 
236
    }
 
237
 
 
238
  for (;;)
 
239
    {
 
240
      mp_limb_t asign;
 
241
      /* Figure out exact size of V.  */
 
242
      vsize = size;
 
243
      MPN_NORMALIZE (vp, vsize);
 
244
      if (vsize <= 1)
 
245
        break;
 
246
 
 
247
      if (use_double_flag)
 
248
        {
 
249
          mp_limb_t uh, vh, ul, vl;
 
250
          /* Let UH,UL be the most significant limbs of U, and let VH,VL be
 
251
             the corresponding bits from V.  */
 
252
          uh = up[size - 1];
 
253
          vh = vp[size - 1];
 
254
          ul = up[size - 2];
 
255
          vl = vp[size - 2];
 
256
          count_leading_zeros (cnt, uh);
 
257
          if (cnt != 0)
 
258
            {
 
259
              uh = (uh << cnt) | (ul >> (BITS_PER_MP_LIMB - cnt));
 
260
              vh = (vh << cnt) | (vl >> (BITS_PER_MP_LIMB - cnt));
 
261
              vl <<= cnt;
 
262
              ul <<= cnt;
 
263
              if (size >= 3)
 
264
                {
 
265
                  ul |= (up[size - 3] >> (BITS_PER_MP_LIMB - cnt));
 
266
                  vl |= (vp[size - 3] >> (BITS_PER_MP_LIMB - cnt));
 
267
                }
 
268
            }
 
269
 
 
270
          A = 1;
 
271
          B = 0;
 
272
          C = 0;
 
273
          D = 1;
 
274
 
 
275
          asign = 0;
 
276
          for (;;)
 
277
            {
 
278
              mp_limb_t T;
 
279
              mp_limb_t qh, q1, q2;
 
280
              mp_limb_t nh, nl, dh, dl;
 
281
              mp_limb_t t1, t0;
 
282
              mp_limb_t Th, Tl;
 
283
 
 
284
              sub_ddmmss (dh, dl, vh, vl, 0, C);
 
285
              if ((dl | dh) == 0)
 
286
                break;
 
287
              add_ssaaaa (nh, nl, uh, ul, 0, A);
 
288
              q1 = div2 (&qh, nh, nl, dh, dl);
 
289
              if (qh != 0)
 
290
                break;          /* could handle this */
 
291
 
 
292
              add_ssaaaa (dh, dl, vh, vl, 0, D);
 
293
              if ((dl | dh) == 0)
 
294
                break;
 
295
              sub_ddmmss (nh, nl, uh, ul, 0, B);
 
296
              q2 = div2 (&qh, nh, nl, dh, dl);
 
297
              if (qh != 0)
 
298
                break;          /* could handle this */
 
299
 
 
300
              if (q1 != q2)
 
301
                break;
 
302
 
 
303
              asign = ~asign;
 
304
 
 
305
              T = A + q1 * C;
 
306
              A = C;
 
307
              C = T;
 
308
              T = B + q1 * D;
 
309
              B = D;
 
310
              D = T;
 
311
              umul_ppmm (t1, t0, q1, vl);
 
312
              t1 += q1 * vh;
 
313
              sub_ddmmss (Th, Tl, uh, ul, t1, t0);
 
314
              uh = vh, ul = vl;
 
315
              vh = Th, vl = Tl;
 
316
 
 
317
              add_ssaaaa (dh, dl, vh, vl, 0, C);
 
318
              sub_ddmmss (nh, nl, uh, ul, 0, A);
 
319
              q1 = div2 (&qh, nh, nl, dh, dl);
 
320
              if (qh != 0)
 
321
                break;          /* could handle this */
 
322
 
 
323
              sub_ddmmss (dh, dl, vh, vl, 0, D);
 
324
              if ((dl | dh) == 0)
 
325
                break;
 
326
              add_ssaaaa (nh, nl, uh, ul, 0, B);
 
327
              q2 = div2 (&qh, nh, nl, dh, dl);
 
328
              if (qh != 0)
 
329
                break;          /* could handle this */
 
330
 
 
331
              if (q1 != q2)
 
332
                break;
 
333
 
 
334
              asign = ~asign;
 
335
 
 
336
              T = A + q1 * C;
 
337
              A = C;
 
338
              C = T;
 
339
              T = B + q1 * D;
 
340
              B = D;
 
341
              D = T;
 
342
              umul_ppmm (t1, t0, q1, vl);
 
343
              t1 += q1 * vh;
 
344
              sub_ddmmss (Th, Tl, uh, ul, t1, t0);
 
345
              uh = vh, ul = vl;
 
346
              vh = Th, vl = Tl;
 
347
            }
 
348
#if EXTEND
 
349
          if (asign)
 
350
            sign = -sign;
 
351
#endif
 
352
        }
 
353
      else /* Same, but using single-limb calculations.  */
 
354
        {
 
355
          mp_limb_t uh, vh;
 
356
          /* Make UH be the most significant limb of U, and make VH be
 
357
             corresponding bits from V.  */
 
358
          uh = up[size - 1];
 
359
          vh = vp[size - 1];
 
360
          count_leading_zeros (cnt, uh);
 
361
          if (cnt != 0)
 
362
            {
 
363
              uh = (uh << cnt) | (up[size - 2] >> (BITS_PER_MP_LIMB - cnt));
 
364
              vh = (vh << cnt) | (vp[size - 2] >> (BITS_PER_MP_LIMB - cnt));
 
365
            }
 
366
 
 
367
          A = 1;
 
368
          B = 0;
 
369
          C = 0;
 
370
          D = 1;
 
371
 
 
372
          asign = 0;
 
373
          for (;;)
 
374
            {
 
375
              mp_limb_t q, T;
 
376
              if (vh - C == 0 || vh + D == 0)
 
377
                break;
 
378
 
 
379
              q = (uh + A) / (vh - C);
 
380
              if (q != (uh - B) / (vh + D))
 
381
                break;
 
382
 
 
383
              asign = ~asign;
 
384
 
 
385
              T = A + q * C;
 
386
              A = C;
 
387
              C = T;
 
388
              T = B + q * D;
 
389
              B = D;
 
390
              D = T;
 
391
              T = uh - q * vh;
 
392
              uh = vh;
 
393
              vh = T;
 
394
 
 
395
              if (vh - D == 0)
 
396
                break;
 
397
 
 
398
              q = (uh - A) / (vh + C);
 
399
              if (q != (uh + B) / (vh - D))
 
400
                break;
 
401
 
 
402
              asign = ~asign;
 
403
 
 
404
              T = A + q * C;
 
405
              A = C;
 
406
              C = T;
 
407
              T = B + q * D;
 
408
              B = D;
 
409
              D = T;
 
410
              T = uh - q * vh;
 
411
              uh = vh;
 
412
              vh = T;
 
413
            }
 
414
#if EXTEND
 
415
          if (asign)
 
416
            sign = -sign;
 
417
#endif
 
418
        }
 
419
 
 
420
#if RECORD
 
421
      max = MAX (A, max);  max = MAX (B, max);
 
422
      max = MAX (C, max);  max = MAX (D, max);
 
423
#endif
 
424
 
 
425
      if (B == 0)
 
426
        {
 
427
          mp_limb_t qh;
 
428
          mp_size_t i;
 
429
          /* This is quite rare.  I.e., optimize something else!  */
 
430
 
 
431
          /* Normalize V (and shift up U the same amount).  */
 
432
          count_leading_zeros (cnt, vp[vsize - 1]);
 
433
          if (cnt != 0)
 
434
            {
 
435
              mp_limb_t cy;
 
436
              mpn_lshift (vp, vp, vsize, cnt);
 
437
              cy = mpn_lshift (up, up, size, cnt);
 
438
              up[size] = cy;
 
439
              size += cy != 0;
 
440
            }
 
441
 
 
442
          qh = mpn_divmod (up + vsize, up, size, vp, vsize);
 
443
#if EXTEND
 
444
          MPN_COPY (tp, s0p, ssize);
 
445
          {
 
446
            mp_size_t qsize;
 
447
 
 
448
            qsize = size - vsize; /* size of stored quotient from division */
 
449
            if (ssize < qsize)
 
450
              {
 
451
                MPN_ZERO (tp + ssize, qsize - ssize);
 
452
                MPN_ZERO (s1p + ssize, qsize); /* zero s1 too */
 
453
                for (i = 0; i < ssize; i++)
 
454
                  {
 
455
                    mp_limb_t cy;
 
456
                    cy = mpn_addmul_1 (tp + i, up + vsize, qsize, s1p[i]);
 
457
                    tp[qsize + i] = cy;
 
458
                  }
 
459
                if (qh != 0)
 
460
                  {
 
461
                    mp_limb_t cy;
 
462
                    cy = mpn_add_n (tp + qsize, tp + qsize, s1p, ssize);
 
463
                    if (cy != 0)
 
464
                      abort ();
 
465
                  }
 
466
              }
 
467
            else
 
468
              {
 
469
                MPN_ZERO (s1p + ssize, qsize); /* zero s1 too */
 
470
                for (i = 0; i < qsize; i++)
 
471
                  {
 
472
                    mp_limb_t cy;
 
473
                    cy = mpn_addmul_1 (tp + i, s1p, ssize, up[vsize + i]);
 
474
                    tp[ssize + i] = cy;
 
475
                  }
 
476
                if (qh != 0)
 
477
                  {
 
478
                    mp_limb_t cy;
 
479
                    cy = mpn_add_n (tp + qsize, tp + qsize, s1p, ssize);
 
480
                    if (cy != 0)
 
481
                      {
 
482
                        tp[qsize + ssize] = cy;
 
483
                        s1p[qsize + ssize] = 0;
 
484
                        ssize++;
 
485
                      }
 
486
                  }
 
487
              }
 
488
            ssize += qsize;
 
489
            ssize -= tp[ssize - 1] == 0;
 
490
          }
 
491
 
 
492
          sign = -sign;
 
493
          MP_PTR_SWAP (s0p, s1p);
 
494
          MP_PTR_SWAP (s1p, tp);
 
495
#endif
 
496
          size = vsize;
 
497
          if (cnt != 0)
 
498
            {
 
499
              mpn_rshift (up, up, size, cnt);
 
500
              mpn_rshift (vp, vp, size, cnt);
 
501
            }
 
502
          MP_PTR_SWAP (up, vp);
 
503
        }
 
504
      else
 
505
        {
 
506
#if EXTEND
 
507
          mp_size_t tsize, wsize;
 
508
#endif
 
509
          /* T = U*A + V*B
 
510
             W = U*C + V*D
 
511
             U = T
 
512
             V = W         */
 
513
 
 
514
#if STAT
 
515
          { mp_limb_t x; x = A | B | C | D; count_leading_zeros (cnt, x);
 
516
          arr[BITS_PER_MP_LIMB - cnt]++; }
 
517
#endif
 
518
          if (A == 0)
 
519
            {
 
520
              /* B == 1 and C == 1 (D is arbitrary) */
 
521
              mp_limb_t cy;
 
522
              MPN_COPY (tp, vp, size);
 
523
              MPN_COPY (wp, up, size);
 
524
              mpn_submul_1 (wp, vp, size, D);
 
525
              MP_PTR_SWAP (tp, up);
 
526
              MP_PTR_SWAP (wp, vp);
 
527
#if EXTEND
 
528
              MPN_COPY (tp, s1p, ssize);
 
529
              tsize = ssize;
 
530
              tp[ssize] = 0;    /* must zero since wp might spill below */
 
531
              MPN_COPY (wp, s0p, ssize);
 
532
              cy = mpn_addmul_1 (wp, s1p, ssize, D);
 
533
              wp[ssize] = cy;
 
534
              wsize = ssize + (cy != 0);
 
535
              MP_PTR_SWAP (tp, s0p);
 
536
              MP_PTR_SWAP (wp, s1p);
 
537
              ssize = MAX (wsize, tsize);
 
538
#endif
 
539
            }
 
540
          else
 
541
            {
 
542
              if (asign)
 
543
                {
 
544
                  mp_limb_t cy;
 
545
                  mpn_mul_1 (tp, vp, size, B);
 
546
                  mpn_submul_1 (tp, up, size, A);
 
547
                  mpn_mul_1 (wp, up, size, C);
 
548
                  mpn_submul_1 (wp, vp, size, D);
 
549
                  MP_PTR_SWAP (tp, up);
 
550
                  MP_PTR_SWAP (wp, vp);
 
551
#if EXTEND
 
552
                  cy = mpn_mul_1 (tp, s1p, ssize, B);
 
553
                  cy += mpn_addmul_1 (tp, s0p, ssize, A);
 
554
                  tp[ssize] = cy;
 
555
                  tsize = ssize + (cy != 0);
 
556
                  cy = mpn_mul_1 (wp, s0p, ssize, C);
 
557
                  cy += mpn_addmul_1 (wp, s1p, ssize, D);
 
558
                  wp[ssize] = cy;
 
559
                  wsize = ssize + (cy != 0);
 
560
                  MP_PTR_SWAP (tp, s0p);
 
561
                  MP_PTR_SWAP (wp, s1p);
 
562
                  ssize = MAX (wsize, tsize);
 
563
#endif
 
564
                }
 
565
              else
 
566
                {
 
567
                  mp_limb_t cy;
 
568
                  mpn_mul_1 (tp, up, size, A);
 
569
                  mpn_submul_1 (tp, vp, size, B);
 
570
                  mpn_mul_1 (wp, vp, size, D);
 
571
                  mpn_submul_1 (wp, up, size, C);
 
572
                  MP_PTR_SWAP (tp, up);
 
573
                  MP_PTR_SWAP (wp, vp);
 
574
#if EXTEND
 
575
                  cy = mpn_mul_1 (tp, s0p, ssize, A);
 
576
                  cy += mpn_addmul_1 (tp, s1p, ssize, B);
 
577
                  tp[ssize] = cy;
 
578
                  tsize = ssize + (cy != 0);
 
579
                  cy = mpn_mul_1 (wp, s1p, ssize, D);
 
580
                  cy += mpn_addmul_1 (wp, s0p, ssize, C);
 
581
                  wp[ssize] = cy;
 
582
                  wsize = ssize + (cy != 0);
 
583
                  MP_PTR_SWAP (tp, s0p);
 
584
                  MP_PTR_SWAP (wp, s1p);
 
585
                  ssize = MAX (wsize, tsize);
 
586
#endif
 
587
                }
 
588
            }
 
589
 
 
590
          size -= up[size - 1] == 0;
 
591
        }
 
592
    }
 
593
 
 
594
#if RECORD
 
595
  printf ("max: %lx\n", max);
 
596
#endif
 
597
 
 
598
#if STAT
 
599
 {int i; for (i = 0; i < BITS_PER_MP_LIMB; i++) printf ("%d:%d\n", i, arr[i]);}
 
600
#endif
 
601
 
 
602
  if (vsize == 0)
 
603
    {
 
604
      if (gp != up && gp != 0)
 
605
        MPN_COPY (gp, up, size);
 
606
#if EXTEND
 
607
      MPN_NORMALIZE (s0p, ssize);
 
608
      if (orig_s0p != s0p)
 
609
        MPN_COPY (orig_s0p, s0p, ssize);
 
610
      *s0size = sign >= 0 ? ssize : -ssize;
 
611
#endif
 
612
      TMP_FREE (mark);
 
613
      return size;
 
614
    }
 
615
  else
 
616
    {
 
617
      mp_limb_t vl, ul, t;
 
618
#if EXTEND
 
619
      mp_size_t qsize, i;
 
620
#endif
 
621
      vl = vp[0];
 
622
#if EXTEND
 
623
      t = mpn_divmod_1 (wp, up, size, vl);
 
624
 
 
625
      MPN_COPY (tp, s0p, ssize);
 
626
 
 
627
      qsize = size - (wp[size - 1] == 0); /* size of quotient from division */
 
628
      if (ssize < qsize)
 
629
        {
 
630
          MPN_ZERO (tp + ssize, qsize - ssize);
 
631
          MPN_ZERO (s1p + ssize, qsize); /* zero s1 too */
 
632
          for (i = 0; i < ssize; i++)
 
633
            {
 
634
              mp_limb_t cy;
 
635
              cy = mpn_addmul_1 (tp + i, wp, qsize, s1p[i]);
 
636
              tp[qsize + i] = cy;
 
637
            }
 
638
        }
 
639
      else
 
640
        {
 
641
          MPN_ZERO (s1p + ssize, qsize); /* zero s1 too */
 
642
          for (i = 0; i < qsize; i++)
 
643
            {
 
644
              mp_limb_t cy;
 
645
              cy = mpn_addmul_1 (tp + i, s1p, ssize, wp[i]);
 
646
              tp[ssize + i] = cy;
 
647
            }
 
648
        }
 
649
      ssize += qsize;
 
650
      ssize -= tp[ssize - 1] == 0;
 
651
 
 
652
      sign = -sign;
 
653
      MP_PTR_SWAP (s0p, s1p);
 
654
      MP_PTR_SWAP (s1p, tp);
 
655
#else
 
656
      t = mpn_mod_1 (up, size, vl);
 
657
#endif
 
658
      ul = vl;
 
659
      vl = t;
 
660
      while (vl != 0)
 
661
        {
 
662
          mp_limb_t t;
 
663
#if EXTEND
 
664
          mp_limb_t q;
 
665
          q = ul / vl;
 
666
          t = ul - q * vl;
 
667
 
 
668
          MPN_COPY (tp, s0p, ssize);
 
669
 
 
670
          MPN_ZERO (s1p + ssize, 1); /* zero s1 too */
 
671
 
 
672
          {
 
673
            mp_limb_t cy;
 
674
            cy = mpn_addmul_1 (tp, s1p, ssize, q);
 
675
            tp[ssize] = cy;
 
676
          }
 
677
 
 
678
          ssize += 1;
 
679
          ssize -= tp[ssize - 1] == 0;
 
680
 
 
681
          sign = -sign;
 
682
          MP_PTR_SWAP (s0p, s1p);
 
683
          MP_PTR_SWAP (s1p, tp);
 
684
#else
 
685
          t = ul % vl;
 
686
#endif
 
687
          ul = vl;
 
688
          vl = t;
 
689
        }
 
690
      if (gp != 0)
 
691
        gp[0] = ul;
 
692
#if EXTEND
 
693
      MPN_NORMALIZE (s0p, ssize);
 
694
      if (orig_s0p != s0p)
 
695
        MPN_COPY (orig_s0p, s0p, ssize);
 
696
      *s0size = sign >= 0 ? ssize : -ssize;
 
697
#endif
 
698
      TMP_FREE (mark);
 
699
      return 1;
 
700
    }
 
701
}