Accessing individual digits of a BigUint in rust - rust

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);
}

Related

Round a Rational64 down to next multiple of a fraction without overflow?

I'm representing numbers as ratios of signed 64-bit integers using the num-rational crate's Rational64 type. I'm trying to round a number down to the next multiple of another number, and I'm getting integer overflow issues when I do it in either of the two obvious ways. Note that both of the numbers may be fractions.
Normalize to an integer
extern crate num_rational;
extern crate num_traits;
use num_rational::Rational64;
use num_traits::identities::Zero;
fn round(mut n: Rational64, increment: Rational64) -> Rational64 {
let rem = n % increment;
if !rem.is_zero() {
// normalize to a multiple of the increment, round down
// to the next integer, and then undo the normalization
n = (n * increment.recip()).trunc() * increment;
}
n
}
fn main() {
let a = Rational64::new(10_000_676_909_441, 8_872_044_800_000_000);
let b = Rational64::new(1, 1_000_000);
let c = round(a, b);
println!("{}", c);
}
(playground)
Subtract the remainder
extern crate num_rational;
extern crate num_traits;
use num_rational::Rational64;
use num_traits::identities::Zero;
fn round(mut n: Rational64, increment: Rational64) -> Rational64 {
let rem = n % increment;
if !rem.is_zero() {
n -= rem;
}
n
}
fn main() {
let a = Rational64::new(10_000_676_909_441, 8_872_044_800_000_000);
let b = Rational64::new(1, 1_000_000);
let c = round(a, b);
println!("{}", c);
}
(playground)
Is there a way to make it so that n is rounded down to a multiple of increment such that integer overflow is less likely? It's fine if I have to extract the numerator and denominator (both Rust i64 types) and do math on them directly.

How to convert a Rust char to an integer so that '1' becomes 1?

I am trying to find the sum of the digits of a given number. For example, 134 will give 8.
My plan is to convert the number into a string using .to_string() and then use .chars() to iterate over the digits as characters. Then I want to convert every char in the iteration into an integer and add it to a variable. I want to get the final value of this variable.
I tried using the code below to convert a char into an integer:
fn main() {
let x = "123";
for y in x.chars() {
let z = y.parse::<i32>().unwrap();
println!("{}", z + 1);
}
}
(Playground)
But it results in this error:
error[E0599]: no method named `parse` found for type `char` in the current scope
--> src/main.rs:4:19
|
4 | let z = y.parse::<i32>().unwrap();
| ^^^^^
This code does exactly what I want to do, but first I have to convert each char into a string and then into an integer to then increment sum by z.
fn main() {
let mut sum = 0;
let x = 123;
let x = x.to_string();
for y in x.chars() {
// converting `y` to string and then to integer
let z = (y.to_string()).parse::<i32>().unwrap();
// incrementing `sum` by `z`
sum += z;
}
println!("{}", sum);
}
(Playground)
The method you need is char::to_digit. It converts char to a number it represents in the given radix.
You can also use Iterator::sum to calculate sum of a sequence conveniently:
fn main() {
const RADIX: u32 = 10;
let x = "134";
println!("{}", x.chars().map(|c| c.to_digit(RADIX).unwrap()).sum::<u32>());
}
my_char as u32 - '0' as u32
Now, there's a lot more to unpack about this answer.
It works because the ASCII (and thus UTF-8) encodings have the Arabic numerals 0-9 ordered in ascending order. You can get the scalar values and subtract them.
However, what should it do for values outside this range? What happens if you provide 'p'? It returns 64. What about '.'? This will panic. And '♥' will return 9781.
Strings are not just bags of bytes. They are UTF-8 encoded and you cannot just ignore that fact. Every char can hold any Unicode scalar value.
That's why strings are the wrong abstraction for the problem.
From an efficiency perspective, allocating a string seems inefficient. Rosetta Code has an example of using an iterator which only does numeric operations:
struct DigitIter(usize, usize);
impl Iterator for DigitIter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.0 == 0 {
None
} else {
let ret = self.0 % self.1;
self.0 /= self.1;
Some(ret)
}
}
}
fn main() {
println!("{}", DigitIter(1234, 10).sum::<usize>());
}
If c is your character you can just write:
c as i32 - 0x30;
Test with:
let c:char = '2';
let n:i32 = c as i32 - 0x30;
println!("{}", n);
output:
2
NB: 0x30 is '0' in ASCII table, easy enough to remember!
Another way is to iterate over the characters of your string and convert and add them using fold.
fn sum_of_string(s: &str) -> u32 {
s.chars().fold(0, |acc, c| c.to_digit(10).unwrap_or(0) + acc)
}
fn main() {
let x = "123";
println!("{}", sum_of_string(x));
}

Rust use of moved value

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.

Normalise ASCII numbers to digit numbers

Running example on play.rust-lang.org
fn main() {
show({
let number = b"123456";
for sequence in number.windows(6) {
let product = sequence.iter().fold(1, |a, &b| a * (b as u64));
println!("product of {:?} is {}", sequence, product);
}
});
}
Instead of having an output like "product of [49, 50, 51, 52, 53, 54] is 15312500000" I need the normal numbers in the brackets and the normalized result for the product.
Trying around with - b'0' to subtract the 48 to get the normal digits in line 5 doesn't work, i.e.
a * ((b as u64) -b'0')
or
(a - b'0') * (b as u64)
Seems I'm missing something here, for example I have no idea what exactly are the 'a' and 'b' values in the fold(). Can anyone enlighten me? :)
Looking at the signature of fold, we can see that it takes two arguments:
fn fold<B, F>(self, init: B, f: F) -> B
where F: FnMut(B, Self::Item) -> B
init, which is of some arbitrary type B, and f, which is a closure that takes a B value and an element from the iterator, in order to compute a new B value. The whole function returns a B. The types are strongly suggestive of what happens: the closure f is repeatedly called on successive elements of the iterator, passing the computed B value into the next f call. Checking the implementation confirms this suspicion:
let mut accum = init;
for x in self {
accum = f(accum, x);
}
accum
It runs through the iterator, passing the accumulated state into the closure in order to compute the next state.
First things first, lets put the type on the fold call:
let product = sequence.iter().fold(1, |a: u64, &b: &u8| a * (b as u64));
That is, the B type we want is u64 (that's what our final product will be), and the item type of the iterator is &u8, a reference to a byte.
Now, we can manually inline the definition of fold to compute product to try to clarify the desired behaviour (I'm ignoring the normalisation for now):
let mut accum = 1;
for x in sequence.iter() {
accum = { // the closure
let a: u64 = accum;
let &b: &u8 = x;
a * b as u64
}
}
let product = accum;
Simplifying:
let mut product = 1;
for &b in sequence.iter() {
product = product * (b as u64)
}
Hopefully this makes it clearer what needs to happen: b runs across each byte, and so it is the value that needs adjustment, to bring the ASCII encoded value down to the expected 0..10 range.
So, you were right with:
a * ((b as u64) -b'0')
However, the details mean that fails to compile, with a type error: b'0' has type u8, but b as u64 as type u64, and it's not legal to use - with u64 and u8. Moving the normalisation to happen before the u64 cast will ensure this works ok, since then you're subtracting b (which is a u8) and a u8:
product * (b - b'0') as u64
All in all, the fold might look clearer (and actually work) as:
let product = sequence.iter()
.fold(1, |prod, &byte| prod * (byte - b'0') as u64);
(I apologise for giving you such confusing code on IRC.)
As an alternative to fold, you can use map and MultiplicativeIterator::product. I find that the two steps help make it clearer what is happening.
#![feature(core)]
use std::iter::MultiplicativeIterator;
fn main() {
let number = b"123456";
for sequence in number.windows(6) {
let product = sequence.iter().map(|v| (v - b'0') as u64).product();
println!("product of {:?} is {}", sequence, product);
}
}
You could even choose to split up the resizing from u8 to u64:
sequence.iter().map(|v| v - b'0').map(|v| v as u64).product();
Nowadays, an alternative is product + to_digit: (itertools was used to print the contents of the iterator)
use {itertools::Itertools, std::char};
fn main() {
let number = b"123456";
let sequence = number
.iter()
.map(|&c| u64::from(char::from(c).to_digit(10).expect("not a digit")));
let product: u64 = sequence.clone().product();
println!("product of {:?} is {}", sequence.format(", "), product);
}
(playground)

How to sum the values in an array, slice, or Vec in Rust?

Editor's note: This question's example is from a version of Rust prior to 1.0 and references types and methods no longer found in Rust. The answers still contain valuable information.
The following code
let mut numbers = new_serial.as_bytes().iter().map(|&x| (x - 48));
let sum = numbers.sum();
results in the following error:
std::iter::Map<,&u8,u8,std::slice::Items<,u8>>` does not implement any method in scope named `sum`
What must I do to sum an array of bytes?
The following works:
for byte in new_serial.as_bytes().iter() {
sum = sum + (byte - 48);
}
Iterator::sum was stabilized in Rust 1.11.0. You can get an iterator from your array/slice/Vec and then use sum:
fn main() {
let a = [1, 2, 3, 4, 5];
let sum: u8 = a.iter().sum();
println!("the total sum is: {}", sum);
}
Of special note is that you need to specify the type to sum into (sum: u8) as the method allows for multiple implementations. See Why can't Rust infer the resulting type of Iterator::sum? for more information.
Applied to your original example:
let new_serial = "01234";
let sum: u8 = new_serial.as_bytes().iter().map(|&x| x - 48).sum();
println!("{}", sum);
As an aside, it's likely more clear if you use b'0' instead of 48.
If performance is important, consider using an implementation that helps the compiler at producing SIMD instructions.
For example, for f32, using 16 lanes (total of 512 bits):
use std::convert::TryInto;
const LANES: usize = 16;
pub fn nonsimd_sum(values: &[f32]) -> f32 {
let chunks = values.chunks_exact(LANES);
let remainder = chunks.remainder();
let sum = chunks.fold([0.0f32; LANES], |mut acc, chunk| {
let chunk: [f32; LANES] = chunk.try_into().unwrap();
for i in 0..LANES {
acc[i] += chunk[i];
}
acc
});
let remainder: f32 = remainder.iter().copied().sum();
let mut reduced = 0.0f32;
for i in 0..LANES {
reduced += sum[i];
}
reduced + remainder
}
pub fn naive_sum(values: &[f32]) -> f32 {
values.iter().sum()
}
for
let values = (0..513).map(|x| x as f32).collect::<Vec<_>>();
the above is 10x faster than values.iter().sum() on my computer:
nonsimd_sum time: [77.341 ns 77.773 ns 78.378 ns]
naive_sum time: [739.97 ns 740.48 ns 740.97 ns]
and ~10% slower than using packed_simd2 (but it does not require nightly).

Resources