Skip to content

Commit 509283d

Browse files
committed
Improve std::num::pow implementation
The implementation has been made more succinct and no longer requires Clone. The coverage of the associated unit test has also been increased to check more combinations of bases, exponents, and expected results.
1 parent cf56624 commit 509283d

File tree

1 file changed

+30
-42
lines changed

1 file changed

+30
-42
lines changed

src/libstd/num/mod.rs

Lines changed: 30 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -304,48 +304,29 @@ pub trait Real: Signed
304304
fn to_radians(&self) -> Self;
305305
}
306306

307-
/// Raises a value to the power of exp, using
308-
/// exponentiation by squaring.
307+
/// Raises a value to the power of exp, using exponentiation by squaring.
309308
///
310309
/// # Example
311310
///
312311
/// ```rust
313312
/// use std::num;
314313
///
315-
/// let sixteen = num::pow(2, 4u);
316-
/// assert_eq!(sixteen, 16);
314+
/// assert_eq!(num::pow(2, 4), 16);
317315
/// ```
318316
#[inline]
319-
pub fn pow<T: Clone+One+Mul<T, T>>(num: T, exp: uint) -> T {
320-
let one: uint = One::one();
321-
let num_one: T = One::one();
322-
323-
if exp.is_zero() { return num_one; }
324-
if exp == one { return num.clone(); }
325-
326-
let mut i: uint = exp;
327-
let mut v: T;
328-
let mut r: T = num_one;
329-
330-
// This if is to avoid cloning self.
331-
if (i & one) == one {
332-
r = r * num;
333-
i = i - one;
334-
}
335-
336-
i = i >> one;
337-
v = num * num;
338-
339-
while !i.is_zero() {
340-
if (i & one) == one {
341-
r = r * v;
342-
i = i - one;
317+
pub fn pow<T: One + Mul<T, T>>(mut base: T, mut exp: uint) -> T {
318+
if exp == 1 { base }
319+
else {
320+
let mut acc = one::<T>();
321+
while exp > 0 {
322+
if (exp & 1) == 1 {
323+
acc = acc * base;
324+
}
325+
base = base * base;
326+
exp = exp >> 1;
343327
}
344-
i = i >> one;
345-
v = v * v;
328+
acc
346329
}
347-
348-
r
349330
}
350331

351332
/// Raise a number to a power.
@@ -1670,17 +1651,24 @@ mod tests {
16701651

16711652
#[test]
16721653
fn test_pow() {
1673-
fn assert_pow<T: Eq+Clone+One+Mul<T, T>>(num: T, exp: uint) -> () {
1674-
assert_eq!(num::pow(num.clone(), exp),
1675-
range(1u, exp).fold(num.clone(), |acc, _| acc * num));
1654+
fn naive_pow<T: One + Mul<T, T>>(base: T, exp: uint) -> T {
1655+
range(0, exp).fold(one::<T>(), |acc, _| acc * base)
16761656
}
1677-
1678-
assert_eq!(num::pow(3, 0), 1);
1679-
assert_eq!(num::pow(5, 1), 5);
1680-
assert_pow(-4, 2);
1681-
assert_pow(8, 3);
1682-
assert_pow(8, 5);
1683-
assert_pow(2u64, 50);
1657+
macro_rules! assert_pow(
1658+
(($num:expr, $exp:expr) => $expected:expr) => {{
1659+
let result = pow($num, $exp);
1660+
assert_eq!(result, $expected);
1661+
assert_eq!(result, naive_pow($num, $exp));
1662+
}}
1663+
)
1664+
assert_pow!((3, 0 ) => 1);
1665+
assert_pow!((5, 1 ) => 5);
1666+
assert_pow!((-4, 2 ) => 16);
1667+
assert_pow!((0.5, 5 ) => 0.03125);
1668+
assert_pow!((8, 3 ) => 512);
1669+
assert_pow!((8.0, 5 ) => 32768.0);
1670+
assert_pow!((8.5, 5 ) => 44370.53125);
1671+
assert_pow!((2u64, 50) => 1125899906842624);
16841672
}
16851673
}
16861674

0 commit comments

Comments
 (0)