Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libcore: add num::Int::pow() and deprecate num::pow(). #19031

Merged
merged 1 commit into from
Nov 18, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 26 additions & 21 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,28 +37,10 @@ pub fn div_rem<T: Div<T, T> + Rem<T, T>>(x: T, y: T) -> (T, T) {
}

/// Raises a `base` to the power of `exp`, using exponentiation by squaring.
///
/// # Example
///
/// ```rust
/// use std::num;
///
/// assert_eq!(num::pow(2i, 4), 16);
/// ```
#[inline]
pub fn pow<T: Int>(mut base: T, mut exp: uint) -> T {
if exp == 1 { base }
else {
let mut acc: T = Int::one();
while exp > 0 {
if (exp & 1) == 1 {
acc = acc * base;
}
base = base * base;
exp = exp >> 1;
}
acc
}
#[deprecated = "Use Int::pow() instead, as in 2i.pow(4)"]
pub fn pow<T: Int>(base: T, exp: uint) -> T {
base.pow(exp)
}

/// A built-in signed or unsigned integer.
Expand Down Expand Up @@ -359,6 +341,29 @@ pub trait Int
None => Int::max_value(),
}
}

/// Raises self to the power of `exp`, using exponentiation by squaring.
///
/// # Example
///
/// ```rust
/// use std::num::Int;
///
/// assert_eq!(2i.pow(4), 16);
/// ```
#[inline]
fn pow(self, mut exp: uint) -> Self {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did the implementation change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified the code by removing the special case for exp==1 because we don't have the move semantics with primitive integers. exp /= 2 is more readable than exp = exp >> 1 and equivalent to it:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing LLVM would optimise to a bit shift anyway.

What do you mean by 'don't have the move semantics with primitive integers'?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc. @huonw

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bjz The original code could move the base parameter to the caller as its return value when exp is 1. It could perhaps achieve better performance only with bigint objects whose initialization cost was not negligible.

let mut base = self;
let mut acc: Self = Int::one();
while exp > 0 {
if (exp & 1) == 1 {
acc = acc * base;
}
base = base * base;
exp /= 2;
}
acc
}
}

macro_rules! checked_op {
Expand Down
6 changes: 3 additions & 3 deletions src/libstd/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,7 @@ mod tests {
}
macro_rules! assert_pow(
(($num:expr, $exp:expr) => $expected:expr) => {{
let result = pow($num, $exp);
let result = $num.pow($exp);
assert_eq!(result, $expected);
assert_eq!(result, naive_pow($num, $exp));
}}
Expand All @@ -775,12 +775,12 @@ mod tests {
mod bench {
extern crate test;
use self::test::Bencher;
use num;
use num::Int;
use prelude::*;

#[bench]
fn bench_pow_function(b: &mut Bencher) {
let v = Vec::from_fn(1024u, |n| n);
b.iter(|| {v.iter().fold(0u, |old, new| num::pow(old, *new));});
b.iter(|| {v.iter().fold(0u, |old, new| old.pow(*new));});
}
}
4 changes: 2 additions & 2 deletions src/test/bench/shootout-binarytrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ fn main() {
let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth);

let mut messages = range_step(min_depth, max_depth + 1, 2).map(|depth| {
use std::num::pow;
let iterations = pow(2i, (max_depth - depth + min_depth) as uint);
use std::num::Int;
let iterations = 2i.pow((max_depth - depth + min_depth) as uint);
Future::spawn(proc() {
let mut chk = 0;
for i in range(1, iterations + 1) {
Expand Down
4 changes: 2 additions & 2 deletions src/test/compile-fail/lint-dead-code-4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

extern crate libc;

use std::num;
use std::num::Int;

struct Foo {
x: uint,
Expand All @@ -23,7 +23,7 @@ struct Foo {
}

fn field_read(f: Foo) -> uint {
num::pow(f.x, 2)
f.x.pow(2)
}

enum XYZ {
Expand Down