@@ -21,6 +21,7 @@ extern crate std;
21
21
22
22
extern crate num_traits as traits;
23
23
24
+ use core:: mem;
24
25
use core:: ops:: Add ;
25
26
26
27
use traits:: { Num , Signed , Zero } ;
@@ -120,6 +121,89 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
120
121
/// ~~~
121
122
fn lcm ( & self , other : & Self ) -> Self ;
122
123
124
+ /// Greatest Common Divisor (GCD) and
125
+ /// Lowest Common Multiple (LCM) together.
126
+ ///
127
+ /// Potentially more efficient than calling `gcd` and `lcm`
128
+ /// individually for identical inputs.
129
+ ///
130
+ /// # Examples
131
+ ///
132
+ /// ~~~
133
+ /// # use num_integer::Integer;
134
+ /// assert_eq!(10.gcd_lcm(&4), (2, 20));
135
+ /// assert_eq!(8.gcd_lcm(&9), (1, 72));
136
+ /// ~~~
137
+ #[ inline]
138
+ fn gcd_lcm ( & self , other : & Self ) -> ( Self , Self ) {
139
+ ( self . gcd ( other) , self . lcm ( other) )
140
+ }
141
+
142
+ /// Greatest common divisor and Bézout coefficients.
143
+ ///
144
+ /// # Examples
145
+ ///
146
+ /// ~~~
147
+ /// # extern crate num_integer;
148
+ /// # extern crate num_traits;
149
+ /// # fn main() {
150
+ /// # use num_integer::{ExtendedGcd, Integer};
151
+ /// # use num_traits::NumAssign;
152
+ /// fn check<A: Copy + Integer + NumAssign>(a: A, b: A) -> bool {
153
+ /// let ExtendedGcd { gcd, x, y, .. } = a.extended_gcd(&b);
154
+ /// gcd == x * a + y * b
155
+ /// }
156
+ /// assert!(check(10isize, 4isize));
157
+ /// assert!(check(8isize, 9isize));
158
+ /// # }
159
+ /// ~~~
160
+ #[ inline]
161
+ fn extended_gcd ( & self , other : & Self ) -> ExtendedGcd < Self >
162
+ where
163
+ Self : Clone ,
164
+ {
165
+ let mut s = ( Self :: zero ( ) , Self :: one ( ) ) ;
166
+ let mut t = ( Self :: one ( ) , Self :: zero ( ) ) ;
167
+ let mut r = ( other. clone ( ) , self . clone ( ) ) ;
168
+
169
+ while !r. 0 . is_zero ( ) {
170
+ let q = r. 1 . clone ( ) / r. 0 . clone ( ) ;
171
+ let f = |mut r : ( Self , Self ) | {
172
+ mem:: swap ( & mut r. 0 , & mut r. 1 ) ;
173
+ r. 0 = r. 0 - q. clone ( ) * r. 1 . clone ( ) ;
174
+ r
175
+ } ;
176
+ r = f ( r) ;
177
+ s = f ( s) ;
178
+ t = f ( t) ;
179
+ }
180
+
181
+ if r. 1 >= Self :: zero ( ) {
182
+ ExtendedGcd {
183
+ gcd : r. 1 ,
184
+ x : s. 1 ,
185
+ y : t. 1 ,
186
+ _hidden : ( ) ,
187
+ }
188
+ } else {
189
+ ExtendedGcd {
190
+ gcd : Self :: zero ( ) - r. 1 ,
191
+ x : Self :: zero ( ) - s. 1 ,
192
+ y : Self :: zero ( ) - t. 1 ,
193
+ _hidden : ( ) ,
194
+ }
195
+ }
196
+ }
197
+
198
+ /// Greatest common divisor, least common multiple, and Bézout coefficients.
199
+ #[ inline]
200
+ fn extended_gcd_lcm ( & self , other : & Self ) -> ( ExtendedGcd < Self > , Self )
201
+ where
202
+ Self : Clone + Signed ,
203
+ {
204
+ ( self . extended_gcd ( other) , self . lcm ( other) )
205
+ }
206
+
123
207
/// Deprecated, use `is_multiple_of` instead.
124
208
fn divides ( & self , other : & Self ) -> bool ;
125
209
@@ -258,6 +342,20 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
258
342
}
259
343
}
260
344
345
+ /// Greatest common divisor and Bézout coefficients
346
+ ///
347
+ /// ```no_build
348
+ /// let e = isize::extended_gcd(a, b);
349
+ /// assert_eq!(e.gcd, e.x*a + e.y*b);
350
+ /// ```
351
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
352
+ pub struct ExtendedGcd < A > {
353
+ pub gcd : A ,
354
+ pub x : A ,
355
+ pub y : A ,
356
+ _hidden : ( ) ,
357
+ }
358
+
261
359
/// Simultaneous integer division and modulus
262
360
#[ inline]
263
361
pub fn div_rem < T : Integer > ( x : T , y : T ) -> ( T , T ) {
@@ -296,6 +394,13 @@ pub fn lcm<T: Integer>(x: T, y: T) -> T {
296
394
x. lcm ( & y)
297
395
}
298
396
397
+ /// Calculates the Greatest Common Divisor (GCD) and
398
+ /// Lowest Common Multiple (LCM) of the number and `other`.
399
+ #[ inline( always) ]
400
+ pub fn gcd_lcm < T : Integer > ( x : T , y : T ) -> ( T , T ) {
401
+ x. gcd_lcm ( & y)
402
+ }
403
+
299
404
macro_rules! impl_integer_for_isize {
300
405
( $T: ty, $test_mod: ident) => {
301
406
impl Integer for $T {
@@ -394,16 +499,36 @@ macro_rules! impl_integer_for_isize {
394
499
m << shift
395
500
}
396
501
502
+ #[ inline]
503
+ fn extended_gcd_lcm( & self , other: & Self ) -> ( ExtendedGcd <Self >, Self ) {
504
+ let egcd = self . extended_gcd( other) ;
505
+ // should not have to recalculate abs
506
+ let lcm = if egcd. gcd. is_zero( ) {
507
+ Self :: zero( )
508
+ } else {
509
+ ( * self * ( * other / egcd. gcd) ) . abs( )
510
+ } ;
511
+ ( egcd, lcm)
512
+ }
513
+
397
514
/// Calculates the Lowest Common Multiple (LCM) of the number and
398
515
/// `other`.
399
516
#[ inline]
400
517
fn lcm( & self , other: & Self ) -> Self {
518
+ self . gcd_lcm( other) . 1
519
+ }
520
+
521
+ /// Calculates the Greatest Common Divisor (GCD) and
522
+ /// Lowest Common Multiple (LCM) of the number and `other`.
523
+ #[ inline]
524
+ fn gcd_lcm( & self , other: & Self ) -> ( Self , Self ) {
401
525
if self . is_zero( ) && other. is_zero( ) {
402
- Self :: zero( )
403
- } else {
404
- // should not have to recalculate abs
405
- ( * self * ( * other / self . gcd( other) ) ) . abs( )
526
+ return ( Self :: zero( ) , Self :: zero( ) ) ;
406
527
}
528
+ let gcd = self . gcd( other) ;
529
+ // should not have to recalculate abs
530
+ let lcm = ( * self * ( * other / gcd) ) . abs( ) ;
531
+ ( gcd, lcm)
407
532
}
408
533
409
534
/// Deprecated, use `is_multiple_of` instead.
@@ -588,6 +713,49 @@ macro_rules! impl_integer_for_isize {
588
713
assert_eq!( ( 11 as $T) . lcm( & 5 ) , 55 as $T) ;
589
714
}
590
715
716
+ #[ test]
717
+ fn test_gcd_lcm( ) {
718
+ use core:: iter:: once;
719
+ for i in once( 0 )
720
+ . chain( ( 1 ..) . take( 127 ) . flat_map( |a| once( a) . chain( once( -a) ) ) )
721
+ . chain( once( -128 ) )
722
+ {
723
+ for j in once( 0 )
724
+ . chain( ( 1 ..) . take( 127 ) . flat_map( |a| once( a) . chain( once( -a) ) ) )
725
+ . chain( once( -128 ) )
726
+ {
727
+ assert_eq!( i. gcd_lcm( & j) , ( i. gcd( & j) , i. lcm( & j) ) ) ;
728
+ }
729
+ }
730
+ }
731
+
732
+ #[ test]
733
+ fn test_extended_gcd_lcm( ) {
734
+ use core:: fmt:: Debug ;
735
+ use traits:: NumAssign ;
736
+ use ExtendedGcd ;
737
+
738
+ fn check<A : Copy + Debug + Integer + NumAssign >( a: A , b: A ) {
739
+ let ExtendedGcd { gcd, x, y, .. } = a. extended_gcd( & b) ;
740
+ assert_eq!( gcd, x * a + y * b) ;
741
+ }
742
+
743
+ use core:: iter:: once;
744
+ for i in once( 0 )
745
+ . chain( ( 1 ..) . take( 127 ) . flat_map( |a| once( a) . chain( once( -a) ) ) )
746
+ . chain( once( -128 ) )
747
+ {
748
+ for j in once( 0 )
749
+ . chain( ( 1 ..) . take( 127 ) . flat_map( |a| once( a) . chain( once( -a) ) ) )
750
+ . chain( once( -128 ) )
751
+ {
752
+ check( i, j) ;
753
+ let ( ExtendedGcd { gcd, .. } , lcm) = i. extended_gcd_lcm( & j) ;
754
+ assert_eq!( ( gcd, lcm) , ( i. gcd( & j) , i. lcm( & j) ) ) ;
755
+ }
756
+ }
757
+ }
758
+
591
759
#[ test]
592
760
fn test_even( ) {
593
761
assert_eq!( ( -4 as $T) . is_even( ) , true ) ;
@@ -674,14 +842,34 @@ macro_rules! impl_integer_for_usize {
674
842
m << shift
675
843
}
676
844
845
+ #[ inline]
846
+ fn extended_gcd_lcm( & self , other: & Self ) -> ( ExtendedGcd <Self >, Self ) {
847
+ let egcd = self . extended_gcd( other) ;
848
+ // should not have to recalculate abs
849
+ let lcm = if egcd. gcd. is_zero( ) {
850
+ Self :: zero( )
851
+ } else {
852
+ * self * ( * other / egcd. gcd)
853
+ } ;
854
+ ( egcd, lcm)
855
+ }
856
+
677
857
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
678
858
#[ inline]
679
859
fn lcm( & self , other: & Self ) -> Self {
860
+ self . gcd_lcm( other) . 1
861
+ }
862
+
863
+ /// Calculates the Greatest Common Divisor (GCD) and
864
+ /// Lowest Common Multiple (LCM) of the number and `other`.
865
+ #[ inline]
866
+ fn gcd_lcm( & self , other: & Self ) -> ( Self , Self ) {
680
867
if self . is_zero( ) && other. is_zero( ) {
681
- Self :: zero( )
682
- } else {
683
- * self * ( * other / self . gcd( other) )
868
+ return ( Self :: zero( ) , Self :: zero( ) ) ;
684
869
}
870
+ let gcd = self . gcd( other) ;
871
+ let lcm = * self * ( * other / gcd) ;
872
+ ( gcd, lcm)
685
873
}
686
874
687
875
/// Deprecated, use `is_multiple_of` instead.
@@ -777,6 +965,15 @@ macro_rules! impl_integer_for_usize {
777
965
assert_eq!( ( 15 as $T) . lcm( & 17 ) , 255 as $T) ;
778
966
}
779
967
968
+ #[ test]
969
+ fn test_gcd_lcm( ) {
970
+ for i in ( 0 ..) . take( 256 ) {
971
+ for j in ( 0 ..) . take( 256 ) {
972
+ assert_eq!( i. gcd_lcm( & j) , ( i. gcd( & j) , i. lcm( & j) ) ) ;
973
+ }
974
+ }
975
+ }
976
+
780
977
#[ test]
781
978
fn test_is_multiple_of( ) {
782
979
assert!( ( 6 as $T) . is_multiple_of( & ( 6 as $T) ) ) ;
0 commit comments