Auto merge of #162 - est31:add_checked_pow, r=cuviper

Add checked_pow function

Implements a `checked_pow` function which does the same as `pow`, just with overflow checks.

And, similar to #152 and #153, the function uses references instead of cloning.

Adds a little macro to spare code repetition. Its scoped to the function so nothing gets polluted.
This commit is contained in:
Homu 2016-02-06 09:01:32 +09:00
commit d1adf45389
1 changed files with 41 additions and 1 deletions

View File

@ -1,4 +1,4 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // Copyright 2014-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at // file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT. // http://rust-lang.org/COPYRIGHT.
// //
@ -164,6 +164,46 @@ pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) ->
acc acc
} }
/// Raises a value to the power of exp, returning `None` if an overflow occured.
///
/// Otherwise same as the `pow` function.
///
/// # Example
///
/// ```rust
/// use num;
///
/// assert_eq!(num::checked_pow(2i8, 4), Some(16));
/// assert_eq!(num::checked_pow(7i8, 8), None);
/// assert_eq!(num::checked_pow(7u32, 8), Some(5_764_801));
/// ```
#[inline]
pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) -> Option<T> {
if exp == 0 { return Some(T::one()) }
macro_rules! optry {
( $ expr : expr ) => {
if let Some(val) = $expr { val } else { return None }
}
}
while exp & 1 == 0 {
base = optry!(base.checked_mul(&base));
exp >>= 1;
}
if exp == 1 { return Some(base) }
let mut acc = base.clone();
while exp > 1 {
exp >>= 1;
base = optry!(base.checked_mul(&base));
if exp & 1 == 1 {
acc = optry!(acc.checked_mul(&base));
}
}
Some(acc)
}
#[cfg(test)] #[cfg(test)]
fn hash<T: hash::Hash>(x: &T) -> u64 { fn hash<T: hash::Hash>(x: &T) -> u64 {
use std::hash::Hasher; use std::hash::Hasher;