pow: avoid unnecessary overflows

The code was performing an extra squaring of the base, which might
trigger an arithmetic overflow that doesn't matter to the result.  Now
this squaring is only attempted when enough exp remains to need it.

A new doctest tries pow(6u8, 3), where an extra square would exceed 256.
This commit is contained in:
Josh Stone 2015-03-07 14:12:50 -08:00
parent fbd7d81b44
commit 043a5b2918
1 changed files with 7 additions and 2 deletions

View File

@ -121,7 +121,8 @@ pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
/// ```rust /// ```rust
/// use num; /// use num;
/// ///
/// assert_eq!(num::pow(2i, 4), 16); /// assert_eq!(num::pow(2i8, 4), 16);
/// assert_eq!(num::pow(6u8, 3), 216);
/// ``` /// ```
#[inline] #[inline]
pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T { pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
@ -132,7 +133,11 @@ pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) ->
if (exp & 1) == 1 { if (exp & 1) == 1 {
acc = acc * base.clone(); acc = acc * base.clone();
} }
// avoid overflow if we won't need it
if exp > 1 {
base = base.clone() * base; base = base.clone() * base;
}
exp = exp >> 1; exp = exp >> 1;
} }
acc acc