How to compare i32 with usize - rust

I'm writing a simple insert sort. Here are the relevant codes.
fn main() {
let mut sort_vec = vec![5,2,4,6,1,3];
for j in 1..sort_vec.len() {
let key = sort_vec[j];
let mut i = j - 1;
while i > 0 && sort_vec[i] > key {
sort_vec[i+1] = sort_vec[i];
i = i - 1;
}
sort_vec[i+1] = key;
}
println!("{:?}",sort_vec);
}
It's input is [5, 1, 2, 3, 4, 6].
The problem was when while i > 0 becomes while i >= 0 or while i > -1,it won't work.
So is there a problem comparing i32 with usize? I tried some methods and couldn't succeed. So how should I handle it? Be deeply grateful!

If you change while i > 0 to while i >= 0 the compiler gives you a warning:
warning: comparison is useless due to type limits
--> src\main.rs:9:15
|
9 | while i >= 0 && sort_vec[i] > key {
| ^^^^^^
|
= note: `#[warn(unused_comparisons)]` on by default
and the code panicks at runtime:
thread 'main' panicked at 'attempt to subtract with overflow', src\main.rs:11:17
The problem is that if i goes down to 0 and you try to subtract 1, the integer i overflows because its type is usize which has to be non-negative.
Because usize can't be negative your comparison i >= 0 is always true (that's the compiler warning).
I would recommend changing the logic a bit: Don't compare the second last element with the next one but compare the last element with the previous one.
So you have to start not at j - 1 but at j, and replace because of that in the following lines i in every index with i - 1:
sort_vec[i] -> sort_vec[i - 1]
sort_vec[i + 1] -> sort_vec[i]
working code:
fn main() {
let mut sort_vec = vec![5, 2, 4, 6, 1, 3];
for j in 1..sort_vec.len() {
let key = sort_vec[j];
let mut i = j;
while i > 0 && sort_vec[i - 1] > key {
sort_vec[i] = sort_vec[i - 1];
i = i - 1;
}
sort_vec[i] = key;
}
println!("{:?}", sort_vec);
}
Now you can see the unnecessary assignment let mut i = j. You could change the head of the for-loop to for mut j in ... to remove that and replace all i with j.
fn main() {
let mut sort_vec = vec![5, 2, 4, 6, 1, 3];
for mut j in 1..sort_vec.len() {
let key = sort_vec[j];
while j > 0 && sort_vec[j - 1] > key {
sort_vec[j] = sort_vec[j - 1];
j = j - 1;
}
sort_vec[j] = key;
}
println!("{:?}", sort_vec);
}

Here there's a nice trick (note that in Rust, wrapping arithmetic has to be explicit or it will panic in debug mode):
while i < j && sort_vec[i] > key {
sort_vec[i + 1] = sort_vec[i];
i = i.wrapping_sub(1);
}
sort_vec[i.wrapping_add(1)] = key;
Playground.
The idea is that we let i underflow then overflow back - but when it'll underflow it will be no longer less than j, so the loop will stop.

i has type usize, so it can never be less than 0. Therefore i >= 0 or i >= -1 are always true. One way to fix your issue is to use a for loop with a reversed range:
fn main() {
let mut sort_vec = vec![5, 2, 4, 6, 1, 3];
for j in 1..sort_vec.len() {
for i in (0..j).rev() {
if sort_vec[i+1] < sort_vec[i] {
sort_vec.swap (i, i+1);
} else {
break;
}
}
}
println!("{:?}", sort_vec);
}
Playground

Related

Getting "Use of moved value" in a loop

I'm making Tic-tac-toe in Rust. I want to count the amount of cells in a line, when the player is moving. Like -- x --. So I call count_result two times with the same dx and dy (that's why I pass dx and dy by reference). But here's the problem. My linter in IntelliJ IDEA complains that I use moved value. The compiler compiles without any warnings. What is the problem? Can you help me?
IntelliJ IDEA screenshot
Just to clarify - game_data.board is [[Option<Cell>; 3]; 3]
struct Data {
board: [[Option<Cell>; 3]; 3],
}
fn count_result(game_data: &Data, point: &Point, cell: &Cell, dx: &isize, dy: &isize) -> isize {
let mut count: isize = 0;
let point = (*point).clone();
let mut x = point.x;
let mut y = point.y;
while (x + dx < 3 && x + dx >= 0) && (y + dy >= 0 && y + dy < 3) {
x += 1;
y += 1;
if game_data.board[x as usize][y as usize] == Some(*cell) {
count += 1;
} else {
break;
}
}
count
}
Here is another example of the same problem.
game_data: &mut Data
IntelliJ IDEA screenshot
This is just a linter indexing invalid state. Just invalidate caches and you'll be fine.

Floating point addition algorithm

I'm attempting to write an addition algorithm of two floating point numbers in Rust. I have nearly got it to work, but there are a few cases when the final mantissa is one off from what it should be. (I'm not yet dealing with subnormal numbers). My algorithm is:
fn add_f32(a: f32, b: f32) -> f32 {
let a_bits = a.to_bits();
let b_bits = b.to_bits();
let a_exp = (a_bits << 1) >> (23 + 1);
let b_exp = (b_bits << 1) >> (23 + 1);
let mut a_mant = a_bits & 0x007fffff;
let mut b_mant = b_bits & 0x007fffff;
let mut a_exp = (a_exp as i32).wrapping_sub(127);
let mut b_exp = (b_exp as i32).wrapping_sub(127);
if b_exp > a_exp {
// If b has a larger exponent than a, swap a and b so that a has the larger exponent
core::mem::swap(&mut a_mant, &mut b_mant);
core::mem::swap(&mut a_exp, &mut b_exp);
}
let exp_diff = (a_exp - b_exp) as u32;
// Add the implicit leading 1 bit to the mantissas
a_mant |= 1 << 23;
b_mant |= 1 << 23;
// Append an extra bit to the mantissas to ensure correct rounding
a_mant <<= 1;
b_mant <<= 1;
// If the shift causes an overflow, the b_mant is too small so is set to 0
b_mant = b_mant.checked_shr(exp_diff).unwrap_or(0);
let mut mant = a_mant + b_mant;
let overflow = (mant >> 25) != 0;
if !overflow {
// Check to see if we round up
if mant & 1 == 1 {
mant += 1;
}
}
// check for overflow caused by rounding up
let overflow = overflow || (mant >> 25) != 0;
mant >>= 1;
if overflow {
if mant & 1 == 1 {
mant += 1;
}
// Check to see if we round up
mant >>= 1;
a_exp += 1;
}
// Remove implicit leading one
mant <<= 9;
mant >>= 9;
f32::from_bits(mant | ((a_exp.wrapping_add(127) as u32) << 23))
}
For example, the test
#[test]
fn test_add_small() {
let a = f32::MIN_POSITIVE;
let b = f32::from_bits(f32::MIN_POSITIVE.to_bits() + 1);
let c = add_f32(a, b);
let d = a + b;
assert_eq!(c, d);
}
fails, with the actual answer being 00000001000000000000000000000000 (binary representation) and my answer being 00000001000000000000000000000001.
Is anyone able to help me with what is wrong with my code?

Recursion issues in rust [duplicate]

This question already has answers here:
Can I destructure a tuple without binding the result to a new variable in a let/match/for statement?
(3 answers)
Closed 4 years ago.
I have that does the following type of recursion and works as expected:
fn test2(i: isize) -> (isize) {
println!("i={}", i);
return (i + 1);
}
fn main() {
let mut i = 1;
let mut j = 1;
for t in 0..4 {
(i) = test2(i);
}
}
i=1
i=2
i=3
i=4
The problem I have is what I really want is this recursion with multiple feedbacks like this.....
fn test(i: isize, j: isize) -> (isize, isize) {
println!("i={} j={}", i, j);
return (i + 1, j + 1);
}
fn main() {
for t in 0..4 {
let (i, j) = test(i, j);
println!("ii {} jj {}", i, j);
}
}
When I run the code I get the below:
i=1 j=1
ii 2 jj 2
i=1 j=1
ii 2 jj 2
i=1 j=1
ii 2 jj 2
i=1 j=1
ii 2 jj 2
If I leave off the let I get the below error:
for t in 0 .. 4 {
(i,j) = test(i, j);
println!("ii {} jj {}", i,j) ;
}
error[E0070]: invalid left-hand side expression
--> src/main.rs:265:13
|
265 | (i,j) = test(i, j);
| ^^^^^^^^^^^^^^^^^^ left-hand of expression not valid
How do I resolve?
This feature is not currently available in Rust. There is an open issue on the issue tracker relating to it. For now, you have to destructure by hand.
let (i1, j1) = test(i, j);
i = i1;
j = j1;

Is there a way to construct a conditional from an array?

Given the following two arrays, is there a way to construct a conditional from b to use in a loop of values in a like the following code? I would like is_divisible to look something like (i % 3 == 0) || (i % 5 == 0) || (i % 7 == 0)
fn main() {
let a: Vec<u32> = vec![80, 90, 101, 254];
let b: Vec<u32> = vec![3, 5, 7];
let is_divisible = // ???
for i in a {
if is_divisible {
println!("{} is true", i);
}
}
}
You can create a closure that uses b and does whatever logic you need. In this case, you can use Iterator::any and Iterator::all to test if all the values meet some criteria:
let is_divisible = |i| {
b.iter().any(|b| i % b == 0)
};
I wouldn't usually write it as a separate variable and I'd use Iterator::filter instead of the if:
for i in a.iter().filter(|&i| b.iter().any(|&b| i % b == 0)) {
println!("{} is true", i);
}

How to use multiple variables in Rust's for loop?

In the C family of languages, I can do this on one line:
for(int i = lo, int j = mid+1; i <= mid && j <= hi; i++, j++){
...
}
But in Rust... I can only write it like this:
for i in lo..mid+1 {
let mut j = mid+1;
if j <= hi {
break;
}
...
j += 1;
}
Is there's a more efficient way to implement this?
Using an iterator works for above, but using an iterator makes some occasions like using arithmetic troublesome, such as
for (int i = 0; i < n; i ++) {
if (a[i] == ...) {
i += 5;
}
}
In Rust, this does not work. The variable i will not be incremented by 5, but by 1 instead:
for i in 0..n {
if a[i] == ... {
i += 5;
}
}
You can create two parallel range iterators, zip them, then iterate though the combination:
fn main() {
let values = [10, 20, 30, 40, 50, 60, 70, 80, 90];
let lo = 2;
let mid = 5;
let hi = 7;
let early_indexes = lo..(mid + 1);
let late_indexes = (mid + 1)..(hi + 1);
for (i, j) in early_indexes.zip(late_indexes) {
println!("{}, {}", i, j);
println!("{} - {}", values[i], values[j]);
}
}
Someday, inclusive ranges will be stabilized, and you should be able to something like this (depending on the eventual syntax):
let early_indexes = lo...mid;
let late_indexes = (mid + 1)...hi;
for (i, j) in early_indexes.zip(late_indexes) {
println!("{}, {}", i, j);
println!("{} - {}", values[i], values[j]);
}
If you are actually iterating though a slice as I've shown for my example, you can also just combine the two iterators directly and ignore the index:
let early_values = values[lo..(mid + 1)].iter();
let late_values = values[(mid + 1)..(hi + 1)].iter();
for (i, j) in early_values.zip(late_values) {
println!("{}, {}", i, j);
}
The variable i will not be incremented by 5, but by 1 instead.
Yes, incrementing by a step is annoying, and some day it will also be stabilized. In the meantime:
What is a stable way to iterate on a range with custom step?
How do I iterate over a range with a custom step?
If you need full control, you can always use while or loop:
let mut i = 0;
while i < n {
if a[i] == ... {
i += 5;
}
i += 1;
}

Resources