@@ -22,7 +22,7 @@ extern crate std;
2222
2323extern crate num_traits as traits;
2424
25- use core:: ops:: Add ;
25+ use core:: ops:: { Add , Neg , Shr } ;
2626use core:: mem;
2727use core:: cmp:: Ordering ;
2828
@@ -735,6 +735,30 @@ pub fn inverse<T: Integer + NumRef + Clone>(a: T, n: &T) -> Option<T>
735735 }
736736}
737737
738+ /// Calculate base^exp (mod modulus).
739+ pub fn powm < T > ( base : & T , exp : & T , modulus : & T ) -> T
740+ where T : Integer + NumRef + Clone + Neg < Output = T > + Shr < i32 , Output = T > ,
741+ for < ' a > & ' a T : RefNum < T >
742+ {
743+ let zero = T :: zero ( ) ;
744+ let one = T :: one ( ) ;
745+ let two = & one + & one;
746+ let mut exp = exp. clone ( ) ;
747+ let mut result = one. clone ( ) ;
748+ let mut base = base % modulus;
749+ if exp < zero {
750+ exp = -exp;
751+ base = inverse ( base, modulus) . unwrap ( ) ;
752+ }
753+ while exp > zero {
754+ if & exp % & two == one {
755+ result = ( result * & base) % modulus;
756+ }
757+ exp = exp >> 1 ;
758+ base = ( & base * & base) % modulus;
759+ }
760+ result
761+ }
738762
739763/// An iterator over binomial coefficients.
740764pub struct IterBinomial < T > {
@@ -901,6 +925,12 @@ fn test_inverse() {
901925 assert_eq ! ( inverse( 5 , & 7 ) . unwrap( ) , 3 ) ;
902926}
903927
928+ #[ test]
929+ fn test_powm ( ) {
930+ // `i64::pow` would overflow.
931+ assert_eq ! ( powm( & 11 , & 19 , & 7 ) , 4 ) ;
932+ }
933+
904934#[ test]
905935fn test_iter_binomial ( ) {
906936 macro_rules! check_simple {
0 commit comments