I was trying to raise an integer to a power using the caret operator (^), but I am getting surprising results, e.g.:
assert_eq!(2^10, 8);
How can I perform exponentiation in Rust?
Rust provides exponentiation via methods pow and checked_pow. The latter
guards against overflows. Thus, to raise 2 to the power of 10, do:
let base: i32 = 2; // an explicit type is required
assert_eq!(base.pow(10), 1024);
The caret operator ^ is not used for exponentiation, it's the bitwise XOR
operator.
Here is the simplest method which you can use:
let a = 2; // Can also explicitly define type i.e. i32
let a = i32::pow(a, 10);
It will output "2 raised to the power of 10", i.e.:
1024
For integers:
fn main() {
let n = u32::pow(2, 10);
println!("{}", n == 1024);
}
For floats:
fn main() {
// example 1
let f = f32::powf(2.0, 10.0);
// example 2
let g = f32::powi(2.0, 10);
// print
println!("{}", f == 1024.0 && g == 1024.0);
}
or, since your base is 2, you can also use shift:
fn main() {
let n = 2 << 9;
println!("{}", n == 1024);
}
https://doc.rust-lang.org/std/primitive.f32.html#method.powf
https://doc.rust-lang.org/std/primitive.f32.html#method.powi
https://doc.rust-lang.org/std/primitive.u32.html#method.pow
I was trying the same thing as the OP. Thanks to the other answer authors.
Here's a variation that works for me:
let n = 2u32.pow(10);
This uses a literal unsigned 32 bit integer to set the type and base, then calls the pow() function on it.
Bit shifting is a good way to do this particular case:
assert_eq!(1 << 10, 1024);
Related
Example code:
use num_bigint::BigUint;
use num_traits::identities::One;
fn main() {
// Example: 10001 (17) => 1110 (14)
let n = BigUint::from(17u32);
println!("{}", n);
// BigUint doesn't support `!`
//let n = !n;
let mask = (BigUint::one() << n.bits()) - 1u32;
let n = n ^ mask;
println!("{}", n);
}
The above code is doing a binary complement of a BigUint using a bit mask. Questions:
Is there a better way to do the binary complement than with a mask? It seems BigUint doesn't include the ! operator (but the mask may be necessary anyway depending on how ! was defined).
If not is there a better way to generate the mask? (Caching masks helps, but can use lots of memory.)
More context with the problem I'm actually looking at: binary complement sequences
If you alternate multiplying by 3 and bit flipping a number some interesting sequences arise. Example starting with 3:
0. 3 (11b) => 3*3 = 9 (1001b) => bit complement is 6 (0110b)
1. 6 (110b)
2. 13 (1101b)
3. 24 (11000b)
4. 55 (110111b)
5. 90 (1011010b)
6. 241 (11110001b)
7. 300 (100101100b)
8. 123 (1111011b)
9. 142 (10001110b)
11. 85 (1010101b)
12. 0 (0b)
One question is whether it reaches zero for all starting numbers or not. Some meander around for quite a while before reaching zero (425720 takes 87,037,147,316 iterations to reach 0). Being able to compute this efficiently can help in answering these questions. Mostly I'm learning a bit more rust with this though.
If you are looking for performance, num-bigint probably isn't the best choice. Everything that is really high-performance, though, seems to be GPL licensed.
Either way, here is a solution using the rug library, which directly supports !(not), and seems to be really fast:
use rug::{ops::NotAssign, Integer};
fn main() {
// Example: 10001 (17) => 1110 (14)
let mut n = Integer::from(17u32);
println!("{}", n);
n.not_assign();
n.keep_bits_mut(n.significant_bits() - 1);
println!("{}", n);
}
17
14
Note that not_assign also inverts the sign bit. We can remove that bit through the keep_bits_mut function.
For example, here is a version of your algorithm:
use rug::{ops::NotAssign, Integer};
fn step(n: &mut Integer) {
*n *= 3;
n.not_assign();
n.keep_bits_mut(n.significant_bits() - 1);
}
fn main() {
let mut n = Integer::from(3);
println!("{}", n);
while n != 0 {
step(&mut n);
println!("{}", n);
}
}
3
6
13
24
55
90
241
300
123
142
85
0
The best solution is probably to just do it yourself. You perform an allocation each time you create a BigUint which really slows down your program. Since we are not doing complex math, we can simplify most of this to a couple bitwise operations.
After a little bit of tinkering, here is how I implemented it. For convenience, I used the unstable nightly feature bigint_helper_methods to allow for the carrying_add function. This helped simplify the addition process.
#[derive(Debug)]
pub struct BigUintHelper {
words: Vec<u64>,
}
impl BigUintHelper {
pub fn mul3_invert(&mut self) {
let len = self.words.len();
// Multiply everything by 3 by adding it to itself with a bit shift
let mut carry = false;
let mut prev_bit = 0;
for word in &mut self.words[..len - 1] {
let previous = *word;
// Perform the addition operation
let (next, next_carry) = previous.carrying_add((previous << 1) | prev_bit, carry);
// Reset carried values for next round
prev_bit = previous >> (u64::BITS - 1);
carry = next_carry;
// Invert the result as we go to avoid needing another pass
*word = !next;
}
// Perform the last word seperatly since we may need to do the invert differently
let previous = self.words[len - 1];
let (next, next_carry) = previous.carrying_add((previous << 1) | prev_bit, carry);
// Extra word from the combination of the carry bits
match next_carry as u64 + (previous >> (u64::BITS - 1)) {
0 => {
// The carry was 0 so we do the normal process
self.words[len - 1] = invert_bits(next);
self.cleanup_end();
}
1 => {
self.words[len - 1] = !next;
// invert_bits(1) = 0
self.cleanup_end();
}
2 => {
self.words[len - 1] = !next;
// invert_bits(2) = 1
self.words.push(1);
}
_ => unreachable!(),
}
}
/// Remove any high order words without any bits
#[inline(always)]
fn cleanup_end(&mut self) {
while let Some(x) = self.words.pop() {
if x != 0 {
self.words.push(x);
break;
}
}
}
/// Count how many rounds it takes to convert this value to 0.
pub fn count_rounds(&mut self) -> u64 {
let mut rounds = 0;
while !self.words.is_empty() {
self.mul3_invert();
rounds += 1;
}
rounds
}
}
impl From<u64> for BigUintHelper {
fn from(x: u64) -> Self {
BigUintHelper {
words: vec![x],
}
}
}
#[inline(always)]
const fn invert_bits(x: u64) -> u64 {
match x.leading_zeros() {
0 => !x,
y => ((1u64 << (u64::BITS - y)) - 1) ^ x
}
}
Rust Playground
This question already has answers here:
What are the exact semantics of Rust's shift operators?
(2 answers)
Closed 1 year ago.
How to make Unsigned right shift (>>>) in rust? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unsigned_right_shift
For positive numbers you can just use the shift operator >>.
For negative numbers however, I'm going to assume you're dealing with an i32. The behavior in the docs you linked shifts the binary representation of a negative number to the right. Therefore we first need to reinterpret the negative integer as an unsigned integer. The safest way of doing it would be with the use of to_be_bytes and from_be_bytes.
fn main() {
let a: u32 = 5;
let b: u32 = 2;
let c: i32 = -5;
let c_as_u32: u32 = {
let bytes = c.to_be_bytes();
u32::from_be_bytes(bytes)
};
let x = a >> b;
let y = c_as_u32 >> b;
println!("x = {}", x); // x = 1
println!("y = {}", y); // x = 1073741822
}
Where LSB at index 0 and MSB is at index 63. Similarly it should extend to u32 and other types.
let my_num: u64 = 100; // 0b1100100
let msb = get_msb(my_num); // 0
let lsb = get_lsb(my_num); // 0
Correction: MSB should be 0 at the 63rd bit, not 1 at index 6
As explained in the comments, you get the LSB and MSB of u64 with n & 1 and (n >> 63) & 1 respectively.
Doing it completely generically is somewhat of a hassle in Rust, though, because generics require operations like shifting, masking, and even the construction of 1 to be fully specified upfront. However, this is where the num-traits crate comes to the rescue. Along with its cousin num, it is the de facto standard for generic Rust in the field of numerics, providing (among others) the PrimInt trait that makes get_msb() and get_lsb() straightforward:
use num_traits::PrimInt;
pub fn get_lsb<N: PrimInt>(n: N) -> N {
n & N::one()
}
pub fn get_msb<N: PrimInt>(n: N) -> N {
let shift = std::mem::size_of::<N>() * 8 - 1;
(n >> shift) & N::one()
}
fn main() {
assert_eq!(get_lsb(100u32), 0);
assert_eq!(get_lsb(101u32), 1);
assert_eq!(get_msb(100u32), 0);
assert_eq!(get_msb(u32::MAX), 1);
}
Playground
When using below function:
fn factors(number: &BigInt) -> Vec<BigInt> {
let mut n = number.clone();
let mut i: BigInt = ToBigInt::to_bigint(&2).unwrap();
let mut factors = Vec::<BigInt>::new();
while i * i <= n {
if (n % i) == ToBigInt::to_bigint(&1).unwrap() {
i = i + ToBigInt::to_bigint(&1).unwrap();
}
else {
n = n/i as BigInt;
factors.push(i);
}
i = i + ToBigInt::to_bigint(&1).unwrap();
}
if n > i {
factors.push(n);
}
factors
}
I get moved value errors for literally every time i or n is used, starting from the line with while, also in the if. I have read about borrowing, which I understand decently, but this thing I don't understand.
I am not "copying" the value at all, so I don't see anywhere were I could lose ownership of the variables.
Mul (and the other arithmetic operators) take the parameters by value, so i * i move the value i (this is not a problem for primitive numbers because they implement Copy - BigInt does not).
As Mul is implemented for (two) &BigInt, you can do the multiplication (and the other arithmetic operations) with &:
use num::*;
fn factors(number: &BigInt) -> Vec<BigInt> {
let mut n = number.clone();
let mut i = BigInt::from(2);
let mut factors = Vec::new();
while &i * &i <= n {
if (&n % &i) == BigInt::one() {
i = i + BigInt::one();
} else {
n = n / &i;
factors.push(i.clone());
}
i = i + BigInt::one();
}
if n > i {
factors.push(n);
}
factors
}
Note that I also made some simplifications, like omitting the type on Vec::new and using BigInt::from (cannot fail).
Remember that operators in Rust are just syntactic sugar for function calls.
a + b translates to a.add(b).
Primitive types such as i32 implement the trait Copy. Thus, they can be copied into such an add function and do not need to be moved.
I assume the BigInt type you are working with does not implement this trait.
Therefore, in every binary operation you are moving the values.
I'm just learning rust, henceforth this question has probably some trivial answer.
I want to access to individual digits of a rust BigUint. This is for a project Euler puzzle asking the sum of these digits.
I did it like below:
let mut f = func(100);
let mut total: BigUint = Zero::zero();
while f > FromPrimitive::from_uint(0).unwrap() {
let digit = f % FromPrimitive::from_uint(10).unwrap();
f = f / FromPrimitive::from_uint(10).unwrap();
total = total + digit;
}
println!("");
println!("Sum of digits of func(100) = {}", total);
It works, but it's quite frustrating, because I believe these digits are internaly stored as an array, but I can't access to them directly because the underlying data member is private.
Is there any way to do that in a more straightforward way ?
The internal storage of BigUint is a vector of BigDigit, which is an alias for u32, so it probably won't help you a lot to get the sum of base 10 digits.
I doubt casting to String would be an efficient way to compute this, but you can make it a little more straightforward using the div_rem() method from trait Integer. (After all, casting to String does this computation internally.)
extern crate num;
use std::num::Zero;
use num::bigint::BigUint;
use num::integer::Integer;
fn main() {
let mut f = func(100);
let mut total: BigUint = Zero::zero();
let ten: BigUint = FromPrimitive::from_uint(10).unwrap();
while f > Zero::zero() {
let (quotient, remainder) = f.div_rem(&ten);
f = quotient;
total = total + remainder;
}
println!("");
println!("Sum of digits of func(100) = {}", total);
}
I ended doing it using to_string() as suggested by #C.Quilley. But as #Levans pointed out the internal implementation merely perform a div_rem. I still prefer that version because I see it as more readable and straightforwad.
extern crate num;
use num::bigint::BigUint;
// What this function does is irrelevant
fn func(n: uint) -> BigUint {
let p : BigUint = FromPrimitive::from_uint(n).unwrap();
p*p*p*p*p*p*p*p*p*p*p*p*p
}
fn main() {
let n = 2014u;
let f = func(n);
let total: uint = f.to_string().as_slice().chars()
.fold(0, |a, b| a + b as uint - '0' as uint);
println!("Sum of digits of func({}) = {} : {}", n, f, total);
}