@@ -21,6 +21,7 @@ extern crate std;
2121
2222extern crate num_traits as traits;
2323
24+ use core:: mem;
2425use core:: ops:: Add ;
2526
2627use traits:: { Num , Signed , Zero } ;
@@ -120,6 +121,89 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
120121 /// ~~~
121122 fn lcm ( & self , other : & Self ) -> Self ;
122123
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+
123207 /// Deprecated, use `is_multiple_of` instead.
124208 fn divides ( & self , other : & Self ) -> bool ;
125209
@@ -258,6 +342,20 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
258342 }
259343}
260344
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+
261359/// Simultaneous integer division and modulus
262360#[ inline]
263361pub 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 {
296394 x. lcm ( & y)
297395}
298396
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+
299404macro_rules! impl_integer_for_isize {
300405 ( $T: ty, $test_mod: ident) => {
301406 impl Integer for $T {
@@ -394,16 +499,36 @@ macro_rules! impl_integer_for_isize {
394499 m << shift
395500 }
396501
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+
397514 /// Calculates the Lowest Common Multiple (LCM) of the number and
398515 /// `other`.
399516 #[ inline]
400517 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 ) {
401525 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( ) ) ;
406527 }
528+ let gcd = self . gcd( other) ;
529+ // should not have to recalculate abs
530+ let lcm = ( * self * ( * other / gcd) ) . abs( ) ;
531+ ( gcd, lcm)
407532 }
408533
409534 /// Deprecated, use `is_multiple_of` instead.
@@ -588,6 +713,49 @@ macro_rules! impl_integer_for_isize {
588713 assert_eq!( ( 11 as $T) . lcm( & 5 ) , 55 as $T) ;
589714 }
590715
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+
591759 #[ test]
592760 fn test_even( ) {
593761 assert_eq!( ( -4 as $T) . is_even( ) , true ) ;
@@ -674,14 +842,34 @@ macro_rules! impl_integer_for_usize {
674842 m << shift
675843 }
676844
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+
677857 /// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
678858 #[ inline]
679859 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 ) {
680867 if self . is_zero( ) && other. is_zero( ) {
681- Self :: zero( )
682- } else {
683- * self * ( * other / self . gcd( other) )
868+ return ( Self :: zero( ) , Self :: zero( ) ) ;
684869 }
870+ let gcd = self . gcd( other) ;
871+ let lcm = * self * ( * other / gcd) ;
872+ ( gcd, lcm)
685873 }
686874
687875 /// Deprecated, use `is_multiple_of` instead.
@@ -777,6 +965,15 @@ macro_rules! impl_integer_for_usize {
777965 assert_eq!( ( 15 as $T) . lcm( & 17 ) , 255 as $T) ;
778966 }
779967
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+
780977 #[ test]
781978 fn test_is_multiple_of( ) {
782979 assert!( ( 6 as $T) . is_multiple_of( & ( 6 as $T) ) ) ;
0 commit comments