@@ -336,41 +336,102 @@ macro_rules! define_bignum {
336
336
( self , borrow)
337
337
}
338
338
339
- /// Divide self by another bignum, overwriting `q` with the quotient and `r` with the
340
- /// remainder.
339
+ /// Knuth’s Algorithm D implementation
341
340
pub fn div_rem( & self , d: & $name, q: & mut $name, r: & mut $name) {
342
- // Stupid slow base-2 long division taken from
343
- // https://en.wikipedia.org/wiki/Division_algorithm
344
- // FIXME use a greater base ($ty) for the long division.
345
341
assert!( !d. is_zero( ) ) ;
346
342
let digitbits = <$ty>:: BITS as usize ;
343
+
347
344
for digit in & mut q. base[ ..] {
348
345
* digit = 0 ;
349
346
}
350
347
for digit in & mut r. base[ ..] {
351
348
* digit = 0 ;
352
349
}
353
- r. size = d. size;
354
- q. size = 1 ;
355
- let mut q_is_zero = true ;
356
- let end = self . bit_length( ) ;
357
- for i in ( 0 ..end) . rev( ) {
358
- r. mul_pow2( 1 ) ;
359
- r. base[ 0 ] |= self . get_bit( i) as $ty;
360
- if & * r >= d {
361
- r. sub( d) ;
362
- // Set bit `i` of q to 1.
363
- let digit_idx = i / digitbits;
364
- let bit_idx = i % digitbits;
365
- if q_is_zero {
366
- q. size = digit_idx + 1 ;
367
- q_is_zero = false ;
350
+
351
+ if d. size == 1 {
352
+ let mut tmp = self . clone( ) ;
353
+ let ( _q, rem) = tmp. div_rem_small( d. base[ 0 ] ) ;
354
+ * q = tmp;
355
+ r. base[ 0 ] = rem;
356
+ r. size = 1 ;
357
+ return ;
358
+ }
359
+
360
+ if self . is_zero( ) {
361
+ q. size = 1 ;
362
+ r. size = 1 ;
363
+ return ;
364
+ }
365
+
366
+ q. size = self . size;
367
+ r. size = 1 ;
368
+ r. base[ 0 ] = 0 ;
369
+
370
+ for i in ( 0 ..self . size) . rev( ) {
371
+ r. mul_pow2( digitbits) ;
372
+
373
+ r. base[ 0 ] = self . base[ i] ;
374
+
375
+ while r. size > 1 && r. base[ r. size - 1 ] == 0 {
376
+ r. size -= 1 ;
377
+ }
378
+
379
+ if & * r < d {
380
+ q. base[ i] = 0 ;
381
+ continue ;
382
+ }
383
+
384
+ let r_top = r. base[ r. size - 1 ] as u128 ;
385
+ let r_next = if r. size >= 2 { r. base[ r. size - 2 ] as u128 } else { 0u128 } ;
386
+ let v = ( r_top << digitbits) | r_next;
387
+ let u = d. base[ d. size - 1 ] as u128 ;
388
+
389
+ // initial estimate
390
+ let mut qhat = ( v / u) as $ty;
391
+ let base_limit = if digitbits == 64 {
392
+ // avoid (1u128<<64) overflow: handle separately
393
+ u128 :: MAX as u128
394
+ } else {
395
+ ( 1u128 << digitbits) - 1
396
+ } ;
397
+ if ( qhat as u128 ) > base_limit {
398
+ qhat = base_limit as $ty;
399
+ }
400
+
401
+ let mut prod = d. clone( ) ;
402
+ if qhat != 0 {
403
+ prod. mul_small( qhat) ;
404
+ } else {
405
+ prod. size = 1 ;
406
+ prod. base[ 0 ] = 0 ;
407
+ }
408
+
409
+ while & prod > & * r {
410
+ qhat = qhat - 1 ;
411
+ // we know prod >= d because qhat was at least 1 when prod > r >= d
412
+ prod. sub( d) ;
413
+ }
414
+
415
+ // Set quotient digit
416
+ q. base[ i] = qhat;
417
+
418
+ if qhat != 0 {
419
+ r. sub( & prod) ;
420
+ while r. size > 1 && r. base[ r. size - 1 ] == 0 {
421
+ r. size -= 1 ;
368
422
}
369
- q. base[ digit_idx] |= 1 << bit_idx;
370
423
}
371
424
}
372
- debug_assert!( q. base[ q. size..] . iter( ) . all( |& d| d == 0 ) ) ;
373
- debug_assert!( r. base[ r. size..] . iter( ) . all( |& d| d == 0 ) ) ;
425
+
426
+ let mut qsz = q. size;
427
+ while qsz > 1 && q. base[ qsz - 1 ] == 0 {
428
+ qsz -= 1 ;
429
+ }
430
+ q. size = qsz;
431
+
432
+ if r. size == 0 {
433
+ r. size = 1 ;
434
+ }
374
435
}
375
436
}
376
437
0 commit comments