@@ -31,43 +31,50 @@ use std::{i64, u64};
31
31
32
32
/**
33
33
A `BigDigit` is a `BigUint`'s composing element.
34
+
35
+ A `BigDigit` is half the size of machine word size.
34
36
*/
35
- pub type BigDigit = u32 ;
37
+ #[ cfg( target_word_size = "32" ) ]
38
+ pub type BigDigit = u16 ;
36
39
37
40
/**
38
- A `DoubleBigDigit` is the internal type used to do the computations. Its
39
- size is the double of the size of `BigDigit`.
41
+ A `BigDigit` is a `BigUint`'s composing element.
42
+
43
+ A `BigDigit` is half the size of machine word size.
40
44
*/
41
- pub type DoubleBigDigit = u64 ;
45
+ #[ cfg( target_word_size = "64" ) ]
46
+ pub type BigDigit = u32 ;
42
47
43
48
pub static ZERO_BIG_DIGIT : BigDigit = 0 ;
44
49
static ZERO_VEC : [ BigDigit , ..1 ] = [ ZERO_BIG_DIGIT ] ;
45
50
46
51
pub mod BigDigit {
47
52
use super :: BigDigit ;
48
- use super :: DoubleBigDigit ;
49
53
50
- // `DoubleBigDigit` size dependent
54
+ #[ cfg( target_word_size = "32" ) ]
55
+ pub static bits: uint = 16 ;
56
+
57
+ #[ cfg( target_word_size = "64" ) ]
51
58
pub static bits: uint = 32 ;
52
59
53
- pub static base: DoubleBigDigit = 1 << bits;
54
- static lo_mask: DoubleBigDigit = ( -1 as DoubleBigDigit ) >> bits;
60
+ pub static base: uint = 1 << bits;
61
+ static lo_mask: uint = ( -1 as uint ) >> bits;
55
62
56
63
#[ inline]
57
- fn get_hi ( n : DoubleBigDigit ) -> BigDigit { ( n >> bits) as BigDigit }
64
+ fn get_hi ( n : uint ) -> BigDigit { ( n >> bits) as BigDigit }
58
65
#[ inline]
59
- fn get_lo ( n : DoubleBigDigit ) -> BigDigit { ( n & lo_mask) as BigDigit }
66
+ fn get_lo ( n : uint ) -> BigDigit { ( n & lo_mask) as BigDigit }
60
67
61
- /// Split one `DoubleBigDigit` into two `BigDigit`s.
68
+ /// Split one machine sized unsigned integer into two `BigDigit`s.
62
69
#[ inline]
63
- pub fn from_doublebigdigit ( n : DoubleBigDigit ) -> ( BigDigit , BigDigit ) {
70
+ pub fn from_uint ( n : uint ) -> ( BigDigit , BigDigit ) {
64
71
( get_hi ( n) , get_lo ( n) )
65
72
}
66
73
67
- /// Join two `BigDigit`s into one `DoubleBigDigit`
74
+ /// Join two `BigDigit`s into one machine sized unsigned integer
68
75
#[ inline]
69
- pub fn to_doublebigdigit ( hi : BigDigit , lo : BigDigit ) -> DoubleBigDigit {
70
- ( lo as DoubleBigDigit ) | ( ( hi as DoubleBigDigit ) << bits)
76
+ pub fn to_uint ( hi : BigDigit , lo : BigDigit ) -> uint {
77
+ ( lo as uint ) | ( ( hi as uint ) << bits)
71
78
}
72
79
}
73
80
@@ -195,8 +202,7 @@ impl Add<BigUint, BigUint> for BigUint {
195
202
196
203
let mut carry = 0 ;
197
204
let mut sum: Vec < BigDigit > = a. data . iter ( ) . zip ( b. data . iter ( ) . chain ( zeros) ) . map ( |( ai, bi) | {
198
- let ( hi, lo) = BigDigit :: from_doublebigdigit (
199
- ( * ai as DoubleBigDigit ) + ( * bi as DoubleBigDigit ) + ( carry as DoubleBigDigit ) ) ;
205
+ let ( hi, lo) = BigDigit :: from_uint ( ( * ai as uint ) + ( * bi as uint ) + ( carry as uint ) ) ;
200
206
carry = hi;
201
207
lo
202
208
} ) . collect ( ) ;
@@ -213,11 +219,8 @@ impl Sub<BigUint, BigUint> for BigUint {
213
219
214
220
let mut borrow = 0 ;
215
221
let diff: Vec < BigDigit > = a. take ( new_len) . zip ( b) . map ( |( ai, bi) | {
216
- let ( hi, lo) = BigDigit :: from_doublebigdigit (
217
- BigDigit :: base
218
- + ( * ai as DoubleBigDigit )
219
- - ( * bi as DoubleBigDigit )
220
- - ( borrow as DoubleBigDigit )
222
+ let ( hi, lo) = BigDigit :: from_uint (
223
+ BigDigit :: base + ( * ai as uint ) - ( * bi as uint ) - ( borrow as uint )
221
224
) ;
222
225
/*
223
226
hi * (base) + lo == 1*(base) + ai - bi - borrow
@@ -271,8 +274,8 @@ impl Mul<BigUint, BigUint> for BigUint {
271
274
272
275
let mut carry = 0 ;
273
276
let mut prod: Vec < BigDigit > = a. data . iter ( ) . map ( |ai| {
274
- let ( hi, lo) = BigDigit :: from_doublebigdigit (
275
- ( * ai as DoubleBigDigit ) * ( n as DoubleBigDigit ) + ( carry as DoubleBigDigit )
277
+ let ( hi, lo) = BigDigit :: from_uint (
278
+ ( * ai as uint ) * ( n as uint ) + ( carry as uint )
276
279
) ;
277
280
carry = hi;
278
281
lo
@@ -437,10 +440,10 @@ impl Integer for BigUint {
437
440
let mut d = Vec :: with_capacity ( an. len ( ) ) ;
438
441
let mut carry = 0 ;
439
442
for elt in an. iter ( ) . rev ( ) {
440
- let ai = BigDigit :: to_doublebigdigit ( carry, * elt) ;
441
- let di = ai / ( bn as DoubleBigDigit ) ;
443
+ let ai = BigDigit :: to_uint ( carry, * elt) ;
444
+ let di = ai / ( bn as uint ) ;
442
445
assert ! ( di < BigDigit :: base) ;
443
- carry = ( ai % ( bn as DoubleBigDigit ) ) as BigDigit ;
446
+ carry = ( ai % ( bn as uint ) ) as BigDigit ;
444
447
d. push ( di as BigDigit )
445
448
}
446
449
d. reverse ( ) ;
@@ -512,14 +515,39 @@ impl ToPrimitive for BigUint {
512
515
} )
513
516
}
514
517
515
- // `DoubleBigDigit` size dependent
518
+ #[ cfg( target_word_size = "32" ) ]
519
+ #[ inline]
520
+ fn to_u64 ( & self ) -> Option < u64 > {
521
+ match self . data . len ( ) {
522
+ 0 => Some ( 0 ) ,
523
+ 1 => Some ( self . data . as_slice ( ) [ 0 ] as u64 ) ,
524
+ 2 => {
525
+ Some ( BigDigit :: to_uint ( self . data . as_slice ( ) [ 1 ] , self . data . as_slice ( ) [ 0 ] ) as u64 )
526
+ }
527
+ 3 => {
528
+ let n_lo = BigDigit :: to_uint ( self . data . as_slice ( ) [ 1 ] , self . data . as_slice ( ) [ 0 ] ) as
529
+ u64 ;
530
+ let n_hi = self . data . as_slice ( ) [ 2 ] as u64 ;
531
+ Some ( ( n_hi << 32 ) + n_lo)
532
+ }
533
+ 4 => {
534
+ let n_lo = BigDigit :: to_uint ( self . data . as_slice ( ) [ 1 ] , self . data . as_slice ( ) [ 0 ] )
535
+ as u64 ;
536
+ let n_hi = BigDigit :: to_uint ( self . data . as_slice ( ) [ 3 ] , self . data . as_slice ( ) [ 2 ] )
537
+ as u64 ;
538
+ Some ( ( n_hi << 32 ) + n_lo)
539
+ }
540
+ _ => None
541
+ }
542
+ }
543
+
544
+ #[ cfg( target_word_size = "64" ) ]
516
545
#[ inline]
517
546
fn to_u64 ( & self ) -> Option < u64 > {
518
547
match self . data . len ( ) {
519
548
0 => Some ( 0 ) ,
520
549
1 => Some ( self . data . as_slice ( ) [ 0 ] as u64 ) ,
521
- 2 => Some ( BigDigit :: to_doublebigdigit ( self . data . as_slice ( ) [ 1 ] , self . data . as_slice ( ) [ 0 ] )
522
- as u64 ) ,
550
+ 2 => Some ( BigDigit :: to_uint ( self . data . as_slice ( ) [ 1 ] , self . data . as_slice ( ) [ 0 ] ) as u64 ) ,
523
551
_ => None
524
552
}
525
553
}
@@ -537,10 +565,26 @@ impl FromPrimitive for BigUint {
537
565
}
538
566
}
539
567
540
- // `DoubleBigDigit` size dependent
568
+ #[ cfg( target_word_size = "32" ) ]
569
+ #[ inline]
570
+ fn from_u64 ( n : u64 ) -> Option < BigUint > {
571
+ let n_lo = ( n & 0x0000_0000_FFFF_FFFF ) as uint ;
572
+ let n_hi = ( n >> 32 ) as uint ;
573
+
574
+ let n = match ( BigDigit :: from_uint ( n_hi) , BigDigit :: from_uint ( n_lo) ) {
575
+ ( ( 0 , 0 ) , ( 0 , 0 ) ) => Zero :: zero ( ) ,
576
+ ( ( 0 , 0 ) , ( 0 , n0) ) => BigUint :: new ( vec ! ( n0) ) ,
577
+ ( ( 0 , 0 ) , ( n1, n0) ) => BigUint :: new ( vec ! ( n0, n1) ) ,
578
+ ( ( 0 , n2) , ( n1, n0) ) => BigUint :: new ( vec ! ( n0, n1, n2) ) ,
579
+ ( ( n3, n2) , ( n1, n0) ) => BigUint :: new ( vec ! ( n0, n1, n2, n3) ) ,
580
+ } ;
581
+ Some ( n)
582
+ }
583
+
584
+ #[ cfg( target_word_size = "64" ) ]
541
585
#[ inline]
542
586
fn from_u64 ( n : u64 ) -> Option < BigUint > {
543
- let n = match BigDigit :: from_doublebigdigit ( n ) {
587
+ let n = match BigDigit :: from_uint ( n as uint ) {
544
588
( 0 , 0 ) => Zero :: zero ( ) ,
545
589
( 0 , n0) => BigUint :: new ( vec ! ( n0) ) ,
546
590
( n1, n0) => BigUint :: new ( vec ! ( n0, n1) )
@@ -606,8 +650,8 @@ impl ToStrRadix for BigUint {
606
650
}
607
651
return fill_concat ( convert_base ( self , base) . as_slice ( ) , radix, max_len) ;
608
652
609
- fn convert_base ( n : & BigUint , base : DoubleBigDigit ) -> Vec < BigDigit > {
610
- let divider = base . to_biguint ( ) . unwrap ( ) ;
653
+ fn convert_base ( n : & BigUint , base : uint ) -> Vec < BigDigit > {
654
+ let divider = FromPrimitive :: from_uint ( base ) . unwrap ( ) ;
611
655
let mut result = Vec :: new ( ) ;
612
656
let mut m = n. clone ( ) ;
613
657
while m >= divider {
@@ -665,7 +709,7 @@ impl BigUint {
665
709
/// Creates and initializes a `BigUint`.
666
710
pub fn parse_bytes ( buf : & [ u8 ] , radix : uint ) -> Option < BigUint > {
667
711
let ( base, unit_len) = get_radix_base ( radix) ;
668
- let base_num = match base . to_biguint ( ) {
712
+ let base_num = match FromPrimitive :: from_uint ( base ) {
669
713
Some ( base_num) => base_num,
670
714
None => { return None ; }
671
715
} ;
@@ -712,8 +756,8 @@ impl BigUint {
712
756
713
757
let mut carry = 0 ;
714
758
let mut shifted: Vec < BigDigit > = self . data . iter ( ) . map ( |elem| {
715
- let ( hi, lo) = BigDigit :: from_doublebigdigit (
716
- ( * elem as DoubleBigDigit ) << n_bits | ( carry as DoubleBigDigit )
759
+ let ( hi, lo) = BigDigit :: from_uint (
760
+ ( * elem as uint ) << n_bits | ( carry as uint )
717
761
) ;
718
762
carry = hi;
719
763
lo
@@ -753,9 +797,33 @@ impl BigUint {
753
797
}
754
798
}
755
799
756
- // `DoubleBigDigit` size dependent
800
+ # [ cfg ( target_word_size = "32" ) ]
757
801
#[ inline]
758
- fn get_radix_base ( radix : uint ) -> ( DoubleBigDigit , uint ) {
802
+ fn get_radix_base ( radix : uint ) -> ( uint , uint ) {
803
+ assert ! ( 1 < radix && radix <= 16 ) ;
804
+ match radix {
805
+ 2 => ( 65536 , 16 ) ,
806
+ 3 => ( 59049 , 10 ) ,
807
+ 4 => ( 65536 , 8 ) ,
808
+ 5 => ( 15625 , 6 ) ,
809
+ 6 => ( 46656 , 6 ) ,
810
+ 7 => ( 16807 , 5 ) ,
811
+ 8 => ( 32768 , 5 ) ,
812
+ 9 => ( 59049 , 5 ) ,
813
+ 10 => ( 10000 , 4 ) ,
814
+ 11 => ( 14641 , 4 ) ,
815
+ 12 => ( 20736 , 4 ) ,
816
+ 13 => ( 28561 , 4 ) ,
817
+ 14 => ( 38416 , 4 ) ,
818
+ 15 => ( 50625 , 4 ) ,
819
+ 16 => ( 65536 , 4 ) ,
820
+ _ => fail ! ( )
821
+ }
822
+ }
823
+
824
+ #[ cfg( target_word_size = "64" ) ]
825
+ #[ inline]
826
+ fn get_radix_base ( radix : uint ) -> ( uint , uint ) {
759
827
assert ! ( 1 < radix && radix <= 16 ) ;
760
828
match radix {
761
829
2 => ( 4294967296 , 32 ) ,
@@ -1531,7 +1599,36 @@ mod biguint_tests {
1531
1599
"88887777666655554444333322221111" ) ;
1532
1600
}
1533
1601
1534
- // `DoubleBigDigit` size dependent
1602
+ #[ cfg( target_word_size = "32" ) ]
1603
+ #[ test]
1604
+ fn test_convert_i64 ( ) {
1605
+ fn check ( b1 : BigUint , i : i64 ) {
1606
+ let b2: BigUint = FromPrimitive :: from_i64 ( i) . unwrap ( ) ;
1607
+ assert ! ( b1 == b2) ;
1608
+ assert ! ( b1. to_i64( ) . unwrap( ) == i) ;
1609
+ }
1610
+
1611
+ check ( Zero :: zero ( ) , 0 ) ;
1612
+ check ( One :: one ( ) , 1 ) ;
1613
+ check ( i64:: MAX . to_biguint ( ) . unwrap ( ) , i64:: MAX ) ;
1614
+
1615
+ check ( BigUint :: new ( vec ! ( ) ) , 0 ) ;
1616
+ check ( BigUint :: new ( vec ! ( 1 ) ) , ( 1 << ( 0 * BigDigit :: bits) ) ) ;
1617
+ check ( BigUint :: new ( vec ! ( -1 ) ) , ( 1 << ( 1 * BigDigit :: bits) ) - 1 ) ;
1618
+ check ( BigUint :: new ( vec ! ( 0 , 1 ) ) , ( 1 << ( 1 * BigDigit :: bits) ) ) ;
1619
+ check ( BigUint :: new ( vec ! ( -1 , -1 ) ) , ( 1 << ( 2 * BigDigit :: bits) ) - 1 ) ;
1620
+ check ( BigUint :: new ( vec ! ( 0 , 0 , 1 ) ) , ( 1 << ( 2 * BigDigit :: bits) ) ) ;
1621
+ check ( BigUint :: new ( vec ! ( -1 , -1 , -1 ) ) , ( 1 << ( 3 * BigDigit :: bits) ) - 1 ) ;
1622
+ check ( BigUint :: new ( vec ! ( 0 , 0 , 0 , 1 ) ) , ( 1 << ( 3 * BigDigit :: bits) ) ) ;
1623
+ check ( BigUint :: new ( vec ! ( -1 , -1 , -1 , -1 >> 1 ) ) , i64:: MAX ) ;
1624
+
1625
+ assert_eq ! ( i64 :: MIN . to_biguint( ) , None ) ;
1626
+ assert_eq ! ( BigUint :: new( vec!( -1 , -1 , -1 , -1 ) ) . to_i64( ) , None ) ;
1627
+ assert_eq ! ( BigUint :: new( vec!( 0 , 0 , 0 , 0 , 1 ) ) . to_i64( ) , None ) ;
1628
+ assert_eq ! ( BigUint :: new( vec!( -1 , -1 , -1 , -1 , -1 ) ) . to_i64( ) , None ) ;
1629
+ }
1630
+
1631
+ #[ cfg( target_word_size = "64" ) ]
1535
1632
#[ test]
1536
1633
fn test_convert_i64 ( ) {
1537
1634
fn check ( b1 : BigUint , i : i64 ) {
@@ -1556,7 +1653,35 @@ mod biguint_tests {
1556
1653
assert_eq ! ( BigUint :: new( vec!( -1 , -1 , -1 ) ) . to_i64( ) , None ) ;
1557
1654
}
1558
1655
1559
- // `DoubleBigDigit` size dependent
1656
+ #[ cfg( target_word_size = "32" ) ]
1657
+ #[ test]
1658
+ fn test_convert_u64 ( ) {
1659
+ fn check ( b1 : BigUint , u : u64 ) {
1660
+ let b2: BigUint = FromPrimitive :: from_u64 ( u) . unwrap ( ) ;
1661
+ assert ! ( b1 == b2) ;
1662
+ assert ! ( b1. to_u64( ) . unwrap( ) == u) ;
1663
+ }
1664
+
1665
+ check ( Zero :: zero ( ) , 0 ) ;
1666
+ check ( One :: one ( ) , 1 ) ;
1667
+ check ( u64:: MIN . to_biguint ( ) . unwrap ( ) , u64:: MIN ) ;
1668
+ check ( u64:: MAX . to_biguint ( ) . unwrap ( ) , u64:: MAX ) ;
1669
+
1670
+ check ( BigUint :: new ( vec ! ( ) ) , 0 ) ;
1671
+ check ( BigUint :: new ( vec ! ( 1 ) ) , ( 1 << ( 0 * BigDigit :: bits) ) ) ;
1672
+ check ( BigUint :: new ( vec ! ( -1 ) ) , ( 1 << ( 1 * BigDigit :: bits) ) - 1 ) ;
1673
+ check ( BigUint :: new ( vec ! ( 0 , 1 ) ) , ( 1 << ( 1 * BigDigit :: bits) ) ) ;
1674
+ check ( BigUint :: new ( vec ! ( -1 , -1 ) ) , ( 1 << ( 2 * BigDigit :: bits) ) - 1 ) ;
1675
+ check ( BigUint :: new ( vec ! ( 0 , 0 , 1 ) ) , ( 1 << ( 2 * BigDigit :: bits) ) ) ;
1676
+ check ( BigUint :: new ( vec ! ( -1 , -1 , -1 ) ) , ( 1 << ( 3 * BigDigit :: bits) ) - 1 ) ;
1677
+ check ( BigUint :: new ( vec ! ( 0 , 0 , 0 , 1 ) ) , ( 1 << ( 3 * BigDigit :: bits) ) ) ;
1678
+ check ( BigUint :: new ( vec ! ( -1 , -1 , -1 , -1 ) ) , u64:: MAX ) ;
1679
+
1680
+ assert_eq ! ( BigUint :: new( vec!( 0 , 0 , 0 , 0 , 1 ) ) . to_u64( ) , None ) ;
1681
+ assert_eq ! ( BigUint :: new( vec!( -1 , -1 , -1 , -1 , -1 ) ) . to_u64( ) , None ) ;
1682
+ }
1683
+
1684
+ #[ cfg( target_word_size = "64" ) ]
1560
1685
#[ test]
1561
1686
fn test_convert_u64 ( ) {
1562
1687
fn check ( b1 : BigUint , u : u64 ) {
0 commit comments