From 3c5ecdc6361536b61456bf84fc63ae02731ca15b Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 3 Feb 2016 06:36:01 +0100 Subject: [PATCH] Add checked_pow function --- src/lib.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 3902ae9..d597b2e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 // http://rust-lang.org/COPYRIGHT. // @@ -164,6 +164,46 @@ pub fn pow>(mut base: T, mut exp: usize) -> 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(mut base: T, mut exp: usize) -> Option { + 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)] fn hash(x: &T) -> u64 { use std::hash::Hasher;