I have an issue with the following Rust code:
pub fn median(v: &Vec<i32>) -> f32 {
let len = v.len();
match len % 2 {
0 => (v[len / 2 - 1] + v[len / 2]) as f32 / 2 as f32,
1 => v[(len - 1) / 2] as f32,
}
}
This code doesn't compile due to a 'Non exhaustive patterns' error.
Why is that? What does the % operator return?
The compiler is not smart enough to figure out that the result of len % 2 can only ever be 0 or 1. It demands a match arm for cases where the result is some other value. You can solve this by explicitly saying that those cases are impossible:
match len % 2 {
0 => (v[len / 2 - 1] + v[len / 2]) as f32 / 2 as f32,
1 => v[(len - 1) / 2] as f32,
_ => unreachable!()
}
The _ will match any other value not previously mentioned. The unreachable!() tells the compiler "this code will never execute", but cause a panic!() just in case it does in fact execute. That way, the program is correct all the time at practically no cost.
Future versions of the compiler might figure out that the values 2.. or not possible.
The % is the remainder operator (not to be cofused with the mod-operator).
The simplest fix is to use _ instead of 1:
match len % 2 {
0 => (v[len / 2 - 1] + v[len / 2]) as f32 / 2 as f32,
_ => v[(len - 1) / 2] as f32,
}
Because len is odd and non-negative in the second branch, (len - 1) / 2 is the same as len / 2. I would simplify it like this:
let mid = v.len() / 2;
match v.len() % 2 {
0 => (v[mid - 1] + v[mid]) as f32 / 2.0,
_ => v[mid] as f32,
}
Related
I am trying to do a simple quadratic function that would return number of roots and their values via an enum:
enum QuadraticResult {
None,
OneRoot(f32),
TwoRoots(f32, f32),
}
fn solveQuadratic(a: f32, b: f32, c: f32) -> QuadraticResult {
let delta = b * b - 4.0 * a * c;
match delta {
< 0 => return QuadraticResult::None,
> 0 => return QuadraticResult::TwoRoots(0.0, 1.0),
_ => return QuadraticResult::OneRoot(0.0),
}
}
This doesn't compile as it complains about '<' and '>'. Is there a way to achieve this with match or do I need to use if
You can use a match guard, but that feels more verbose than a plain if statement:
return match delta {
d if d < 0 => QuadraticResult::None,
d if d > 0 => QuadraticResult::TwoRoots(0.0, 1.0),
_ => QuadraticResult::OneRoot(0.0),
}
If you want to handle the three cases where some value is greater than, equal to or less than another, you can match on an Ordering, which you can obtain by calling cmp (from the Ord trait) or partial_cmp (from the PartialOrd trait).
fn solve_quadratic(a: f32, b: f32, c: f32) -> QuadraticResult {
let delta = b * b - 4.0 * a * c;
match delta.partial_cmp(&0.0).expect("I don't like NaNs") {
Ordering::Less => QuadraticResult::None,
Ordering::Greater => QuadraticResult::TwoRoots(0.0, 1.0),
Ordering::Equal => QuadraticResult::OneRoot(0.0),
}
}
You can, but you'll want to create a variable binding when you do it and turn it into an actual expression:
match delta {
d if d < 0.0 => QuadraticResult::None,
d if d > 0.0 => QuadraticResult::TwoRoots(0.0, 1.0),
_ => QuadraticResult::OneRoot(0.0),
}
I'm not sure this is any better than just splitting this into an if statement though.
Warning: as of rustc 1.67.0 (fc594f156 2023-01-24) this method still works, but will stop working for float literals in a future release.
You can use a Range Pattern which are supported in match expressions. This requires the exclusive_range_pattern feature.
#![feature(exclusive_range_pattern)]
fn solveQuadratic(a: f32, b: f32, c: f32) -> QuadraticResult {
let delta = b * b - 4.0 * a * c;
match delta {
std::f32::MIN..0.0 => return QuadraticResult::None,
0.0 => return QuadraticResult::OneRoot(0.0),
_ => return QuadraticResult::TwoRoots(0.0, 1.0),
}
}
Playground
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
As a Rust beginner working on one of the first problems on Exercism/Rust (https://exercism.org/tracks/rust/exercises/assembly-line)
I would like to know if it is possible to constrain integer input to a range at compile-time
to be able to have a clean set of match expression cases.
Below is my current implementation of production_rate_per_hour:
pub fn production_rate_per_hour(mut speed: u8) -> f64 {
speed = cmp::max(speed, 10);
let cars_per_hour: u8 = 221;
match speed {
0 => 0.0,
1 ..= 4 => (speed * cars_per_hour) as f64,
5 ..= 8 => (speed * cars_per_hour) as f64 * 0.9,
9 | 10 => (speed * cars_per_hour) as f64 * 0.77
}
}
I am trying to write a method that accepts a single mutable u8 argument named speed that I then constrain to the range 0..=10 as follows:
speed = cmp::max(speed, 10);
I then want to match speed on all possible cases, i.e. 0..=10.
But since this is a run-time check, the compiler does not see this and tells me to also match integer value 11 and higher:
Compiling assembly-line v0.1.0 (/Users/michahell/Exercism/rust/assembly-line)
error[E0004]: non-exhaustive patterns: `11_u8..=u8::MAX` not covered
--> src/lib.rs:12:11
|
12 | match speed {
| ^^^^^ pattern `11_u8..=u8::MAX` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
I can of course solve this by adding the following case:
// notify
_ => println!("11 or higher")
// or crash
_ => panic!("you've crashed the assembly line!");
// or do something like this:
_ => (cmp::max(speed, 10) * cars_per_hour) as f64 * 0.77;
However, I would like to know if it is possible to constrain the input range at compile-time, and having a "clean" match expression.
Is this possible, if so, how?
There is currently no way to express this in the type system.
I assume you mean min instead of max. The typical approach would be:
pub fn production_rate_per_hour(mut speed: u8) -> f64 {
speed = cmp::min(speed, 10);
let cars_per_hour: u8 = 221;
match speed {
0 => 0.0,
1 ..= 4 => (speed * cars_per_hour) as f64,
5 ..= 8 => (speed * cars_per_hour) as f64 * 0.9,
9 | 10 => (speed * cars_per_hour) as f64 * 0.77,
_ => unreachable!(),
}
}
A bug in your program (e.g., accidentally raising the cap to 11) will result in a panic. If this is performance sensitive, you can use unsafe:
_ => unsafe { std::hint::unreachable_unchecked() },
If your claim that this branch is unreachable is false, you get undefined behavior.
Note that in many cases, the compiler will be able to prove the unreachable branch is, in fact, unreachable and elide it completely. This is very common for e.g. modular arithmetic:
Example
pub fn foo(v: u64) -> u8 {
match v % 8 {
0 => 0,
1 ..= 4 => 1,
5 ..= 7 => 2,
_ => unreachable!(),
}
}
Note that after a slight refactoring:
pub fn production_rate_per_hour(speed: u8) -> f64 {
let speed = speed.min(10);
let factor = match speed {
0 => 0.0_f64,
1 ..= 4 => 1.0,
5 ..= 8 => 0.9,
9.. => 0.77,
};
let cars_per_hour: u8 = 221;
factor * (speed * cars_per_hour) as f64
}
There is no case where unreachable is needed. The tradeoff is you no longer get to be very explicit in the match about what values of speed are acceptable. Whether this or a panic is better depends on your context.
I understand how to operate on an entire vector, though I don't think this is idiomatic Rust:
fn median(v: &Vec<u32>) -> f32 {
let count = v.len();
if count % 2 == 1 {
v[count / 2] as f32
} else {
(v[count / 2] as f32 + v[count / 2 - 1] as f32) / 2.0
}
}
fn main() {
let mut v1 = vec![3, 7, 8, 5, 12, 14, 21, 13, 18];
v1.sort();
println!("{:.*}", 1, median(&v1));
}
But what if I want to operate on only half of this vector? For example, the first quartile is the median of the lower half, and the third quartile is the median of the upper half. My first thought was to construct two new vectors, but that did not seem quite right.
How do I get "half" a vector?
As mentioned, you want to create a slice using the Index trait with a Range:
let slice = &v1[0..v1.len() / 2];
This is yet another reason why it is discouraged to accept a &Vec. The current code would require converting the slice into an allocated Vec. Instead, rewrite it to accept a slice:
fn median(v: &[u32]) -> f32 {
// ...
}
Since you are likely interested in splitting a vector / slice in half and getting both parts, split_at may be relevant:
let (head, tail) = v1.split_at(v1.len() / 2);
println!("{:.*}", 1, median(head));
println!("{:.*}", 1, median(tail));
How to find the median on vector:
fn median(numbers: &mut Vec<i32>) -> i32 {
numbers.sort();
let mid = numbers.len() / 2;
if numbers.len() % 2 == 0 {
mean(&vec![numbers[mid - 1], numbers[mid]]) as i32
} else {
numbers[mid]
}
}
How to get half a vector:
Use Slice:
let slice: &[i32] = &numbers[0..numbers.len() / 2];
Creates a draining iterator
let half: Vec<i32> = numbers.drain(..numbers.len()/2).collect()
I've been trying to generate primes between m and n with the following function:
//the variable sieve is a list of primes between 1 and 32000
//The primes up to 100 are definitely correct
fn sieve_primes(sieve: &Vec<usize>, m: &usize, n: &usize) -> Vec<usize> {
let size: usize = *n - *m + 1;
let mut list: Vec<usize> = Vec::with_capacity(size);
for i in *m..(*n + 1) {
list.push(i);
}
for i in sieve {
for j in ( ((*m as f32) / (*i as f32)).ceil() as usize)..( (((*n as f32) / (*i as f32)).floor() + 1.0) as usize) {
println!("{} ",j);
if j != 1 {list[i * j - *m] = 0;}
}
}
let mut primes: Vec<usize> = Vec::new();
for num in &list{
if *num >= 2 {primes.push(*num);}
}
primes
}
This works for smaller (less than 1000000-ish) values of m and n, but
it fails at runtime for numbers around the billions / hundred-millions.
The output for m = 99999999, n = 100000000 is:
33333334
thread '' panicked at 'index out of bounds: the len is 2 but the index is 3'
If you look at the numbers this doesn't make any sense. First of all, it seems to skip the number 2 in the list of primes. Second, when i = 3 the for statement should simplify to for j in 33333333..333333334, which for some reason starts j at 33333334.
f32 can only represent all 24-bit integers exactly, which corresponds to about 16 million (actually 16777216). Above that there are gaps, up to 33554432 only even numbers can be represented. So in your example 33333333 cannot be represented as f32 and is rounded to 33333334.
You don't need to use float to round the result of an integer division. Using integers directly is both faster and doesn't have precision issues. For non-negative integers you can do the following:
fn main() {
let a = 12;
let b = 7;
println!("rounded down: {}", a / b);
println!("rounded: {}", (a + b / 2) / b);
println!("rounded up: {}", (a + b - 1) / b);
}
You are casting integers to f32, but f32 is not precise enough. Use f64 instead.
fn main() {
println!("{}", 33333333.0f32); // prints 33333332
}