Why does rustc say that the variable "totalSplitInv" is out of scope? - scope

I ran the following program past rustc:
#![feature(slicing_syntax)]
fn sortAndCountInv(arr: &mut [i64]) -> i64 {
return sortAndCountInv_(arr, 0, arr.length - 1)
}
fn sortAndCountInv_(arr: &mut [i64], start: i64, finish: i64) {
let lengthOfSubarray = finish - start + 1;
if (lengthOfSubarray == 0) || (lengthOfSubarray == 1) {
return totalSplitInv
}
else {
let half = (start + finish) / 2;
let leftInv = sortAndCountInv_(arr, start, half);
let rightInv = sortAndCountInv_(arr, half + 1, finish);
let splitInv = mergeAndCountSplitInv(arr, start, finish, half);
return leftInv + rightInv + splitInv
}
}
fn mergeAndCountSplitInv(arr: &mut [i64], start: i64, finish: i64, half: i64) -> i64 {
let aux = arr[start..finish + 1];
let divider = half - start;
let mut i = 0;
let mut j = divider + 1;
let mut totalSplitInv = 0;
let lastIndex = aux.length - 1;
for k in range(start, finish + 1) {
if i > divider {
arr[k] = aux[j];
j += 1
} else if j > lastIndex {
arr[k] = aux[i];
i += 1
} else if aux[i] < aux[j] {
arr[k] = aux[i];
i += 1
} else {
arr[k] = aux[j];
j += 1;
totalSplitInv += (divider - i) + 1;
}
}
return totalSplitInv
}
When I try to compile it with rustc v-0.12.0-dev, I get the following scope error:
inversions.rs:9:16: 9:29 error: unresolved name `totalSplitInv`.
inversions.rs:9 return totalSplitInv
Which is to say, in the function mergeAndCountSplitInv, the line return totalSplitInv is invalid because totalSplitInv is out of scope? Why is this the case?

I think the error is pointing to the return totalSplitInv in sortAndCountInv_, not mergeAndCountSplitInv.
fn sortAndCountInv_(arr: &mut [i64], start: i64, finish: i64) {
let lengthOfSubarray = finish - start + 1;
if (lengthOfSubarray == 0) || (lengthOfSubarray == 1) {
return totalSplitInv // here
...

Related

Canonical way to check for integer overflow in usize

I was trying to solve the following leetcode problem in Rust:
impl Solution {
pub fn merge(nums1: &mut Vec<i32>, m: i32, nums2: &mut Vec<i32>, n: i32) {
let mut backwards_idx: usize = (m + n - 1) as usize;
let (m_size, n_size) = (m as usize, n as usize);
let (mut m_idx, mut n_idx) = ((m-1) as usize, (n-1) as usize);
while 0 <= m_idx && 0 <= n_idx {
let (nums1_elem, nums2_elem) = (nums1[m_idx], nums2[n_idx]);
if nums1_elem <= nums2_elem {
nums1[backwards_idx] = nums2_elem;
n_idx = n_idx - 1;
} else {
nums1[backwards_idx] = nums1_elem;
m_idx = m_idx - 1;
}
backwards_idx = backwards_idx - 1;
}
while 0 <= m_idx {
nums1[backwards_idx] = nums1[m_idx];
m_idx = m_idx - 1;
backwards_idx = backwards_idx - 1;
}
while 0 <= n_idx {
nums1[backwards_idx] = nums2[n_idx];
n_idx = n_idx - 1;
backwards_idx = backwards_idx - 1;
}
}
}
However, this won't work, since m_size and n_size will overflow when subtracted from 0. I know this isn't canonical Rust, but since the problem is given in i32, I can't change it much.
There is the checked method, but that seems pretty hard to read instead of writing it directly it in the while loop condition. Somehow having the exit condition in the body of the while loop doesn't seem like a good idea.
One simple way to avoid having to check for overflow is by guaranteeing that your usize types, which are only ever being subtracted by 1, are never 0 to start in those loops. Refactoring the idx types to be counts, and subtracting by 1 when we want to obtain an index, is one way to do this ...
impl Solution {
pub fn merge(nums1: &mut Vec<i32>, m: i32, nums2: &mut Vec<i32>, n: i32) {
let mut numbers_left: usize = (m + n) as usize;
let (mut m_left, mut n_left) = (m as usize, n as usize);
while m_left > 0 && n_left > 0 {
let (nums1_elem, nums2_elem) = (nums1[m_left-1], nums2[n_left-1]);
if nums1_elem <= nums2_elem {
nums1[numbers_left-1] = nums2_elem;
n_left = n_left - 1;
} else {
nums1[numbers_left-1] = nums1_elem;
m_left = m_left - 1;
}
numbers_left = numbers_left - 1;
}
while m_left > 0 {
nums1[numbers_left-1] = nums1[m_left-1];
m_left = m_left - 1;
numbers_left = numbers_left - 1;
}
while n_idx > 0 {
nums1[numbers_left-1] = nums2[n_left-1];
n_left = n_left - 1;
numbers_left = numbers_left - 1;
}
}
}
A way to avoid overflow, is to structure the loops differently.... Rust doesn't have the explicit do-while syntax, but it does have loop which can you can break from, and even break out to any number of outer loops using labels.
loop {
nums1[backwards_idx] = nums1[m_idx];
if m_idx == 0 { break; }
m_idx -= 1;
backwards_idx -= 1;
}

Merge sort code not giving desired output in rust

I was trying to do a merge sort code in rust.but its not giving the desired output.I tried to debug it for a while but sadly i couldnt find where the error is.
Here is one in Rust Playground.Can you please debug it?
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=25eef03b3d421cc2ae70c3c8a1bb69cb
fn main() {
let mut vec: Vec<u32> = vec![5,7,1,1,3,8,4,4,3,2,1,8,4,9];
let len = vec.len();
let left_index: usize = 0;
let right_index: usize = len - 1;
divide(&mut vec, left_index, right_index);
println!("{:?}",vec);
}
fn divide(mut vec: &mut Vec<u32>, left_index: usize, right_index: usize){
if right_index > left_index {
let middle_index = (left_index + right_index)/2;
divide(&mut vec, left_index, middle_index);
divide(&mut vec, middle_index + 1, right_index);
sort_and_merge(&mut vec, left_index, right_index, middle_index)
}
}
fn sort_and_merge(vec: &mut Vec<u32>, left_index: usize, right_index: usize, middle_index: usize){
let mut vec_left: Vec<u32> = vec![];
let mut vec_right: Vec<u32> = vec![];
for i in left_index..= middle_index{
vec_left.push(vec[i]);
}
for i in (middle_index+1)..= right_index{
vec_right.push(vec[i]);
}
let mut i = 0; // i for vec_left
let mut j = 0; // j for vec_right
let mut k = left_index;
while i < (middle_index - left_index + 1) && j < (right_index - middle_index) {
if vec_left[i] > vec_right[j]{
vec[k] = vec_right[j];
j += 1;
k += 1;
}
else{
vec[k] = vec_left[i];
i += 1;
k += 1;
}
}
while i < vec_left.len(){
vec[k] = vec_left[i];
i += 1;
k += 1;
}
while j < vec_right.len(){
vec[k] = vec_left[j];
j += 1;
k += 1;
}
}
Quoting the code in question:
let mut j = 0; // j for vec_right
...
while j < vec_right.len(){
vec[k] = vec_left[j];
j += 1;
k += 1;
}
In the last part, it seems that you'd want to use vec_right[j].

Insertion sort algorithm gives overflow error

When trying to run the insertion sort algorithm as shown below in Rust 1.15.
fn main() {
println!("The sorted set is now: {:?}", insertion_sort(vec![5,2,4,6,1,3]));
}
fn insertion_sort(set: Vec<i32>) -> Vec<i32> {
let mut A = set.to_vec();
for j in 1..set.len() {
let key = A[j];
let mut i = j - 1;
while (i >= 0) && (A[i] > key) {
A[i + 1] = A[i];
i = i - 1;
}
A[i + 1] = key;
}
A
}
I get the error:
thread 'main' panicked at 'attempt to subtract with overflow', insertion_sort.rs:12
note: Run with `RUST_BACKTRACE=1` for a backtrace
Why does an overflow happen here and how is the problem alleviated?
The reason is you tried to calculate 0 - 1 in usize type, which is unsigned (nonnegative). This may lead to an error in Rust.
Why usize? Because Rust expects usize for lengths and indices. You can explicitly convert them into/from signed ones e.g. isize.
fn main() {
println!("The sorted set is now: {:?}", insertion_sort(vec![5,2,4,6,1,3]));
}
fn insertion_sort(set: Vec<i32>) -> Vec<i32> {
let mut A = set.to_vec();
for j in 1..set.len() as isize {
let key = A[j as usize];
let mut i = j - 1;
while (i >= 0) && (A[i as usize] > key) {
A[(i + 1) as usize] = A[i as usize];
i = i - 1;
}
A[(i + 1) as usize] = key;
}
A
}
Another solution, which I recommend, is to avoid negative indices at all. In this case you can use i + 1 instead of i like this:
fn main() {
println!("The sorted set is now: {:?}", insertion_sort(vec![5,2,4,6,1,3]));
}
fn insertion_sort(set: Vec<i32>) -> Vec<i32> {
let mut A = set.to_vec();
for j in 1..set.len() {
let key = A[j];
let mut i = j;
while (i > 0) && (A[i - 1] > key) {
A[i] = A[i - 1];
i = i - 1;
}
A[i] = key;
}
A
}

How to create a very large array? [duplicate]

I'm implementing combsort. I'd like to create fixed-size array on the stack, but it shows stack overflow. When I change it to be on the heap (Rust by Example says to allocate in the heap we must use Box), it still shows stack overflow.
fn new_gap(gap: usize) -> usize {
let ngap = ((gap as f64) / 1.3) as usize;
if ngap == 9 || ngap == 10 {
return 11;
}
if ngap < 1 {
return 1;
}
return ngap;
}
fn comb_sort(a: &mut Box<[f64]>) {
// previously: [f64]
let xlen = a.len();
let mut gap = xlen;
let mut swapped: bool;
let mut temp: f64;
loop {
swapped = false;
gap = new_gap(gap);
for i in 0..(xlen - gap) {
if a[i] > a[i + gap] {
swapped = true;
temp = a[i];
a[i] = a[i + gap];
a[i + gap] = temp;
}
}
if !(gap > 1 || swapped) {
break;
}
}
}
const N: usize = 10000000;
fn main() {
let mut arr: Box<[f64]> = Box::new([0.0; N]); // previously: [f64; N] = [0.0; N];
for z in 0..(N) {
arr[z] = (N - z) as f64;
}
comb_sort(&mut arr);
for z in 1..(N) {
if arr[z] < arr[z - 1] {
print!("!")
}
}
}
The output:
thread '<main>' has overflowed its stack
Illegal instruction (core dumped)
Or
thread 'main' has overflowed its stack
fatal runtime error: stack overflow
I know that my stack size is not enough, the same as C++ when creating a non-heap array that is too big inside a function, but this code is using heap but still shows stack overflow. What's really wrong with this code?
As far as I can tell, it seems like that code is still trying to allocate the array on the stack first, and then move it into the box after.
It works for me if I switch to Vec<f64> in place of Box<[f64]> like this:
fn new_gap(gap: usize) -> usize {
let ngap = ((gap as f64) / 1.3) as usize;
if ngap == 9 || ngap == 10 {
return 11;
}
if ngap < 1 {
return 1;
}
return ngap;
}
fn comb_sort(a: &mut [f64]) {
// previously: [f64]
let xlen = a.len();
let mut gap = xlen;
let mut swapped: bool;
let mut temp: f64;
loop {
swapped = false;
gap = new_gap(gap);
for i in 0..(xlen - gap) {
if a[i] > a[i + gap] {
swapped = true;
temp = a[i];
a[i] = a[i + gap];
a[i + gap] = temp;
}
}
if !(gap > 1 || swapped) {
break;
}
}
}
const N: usize = 10000000;
fn main() {
let mut arr: Vec<f64> = std::iter::repeat(0.0).take(N).collect();
//let mut arr: Box<[f64]> = Box::new([0.0; N]); // previously: [f64; N] = [0.0; N];
for z in 0..(N) {
arr[z] = (N - z) as f64;
}
comb_sort(arr.as_mut_slice());
for z in 1..(N) {
if arr[z] < arr[z - 1] {
print!("!")
}
}
}
In the future, the box syntax will be stabilized. When it is, it will support this large allocation, as no function call to Box::new will be needed, thus the array will never be placed on the stack. For example:
#![feature(box_syntax)]
fn main() {
let v = box [0i32; 5_000_000];
println!("{}", v[1_000_000])
}

Thread '<main>' has overflowed its stack when allocating a large array using Box

I'm implementing combsort. I'd like to create fixed-size array on the stack, but it shows stack overflow. When I change it to be on the heap (Rust by Example says to allocate in the heap we must use Box), it still shows stack overflow.
fn new_gap(gap: usize) -> usize {
let ngap = ((gap as f64) / 1.3) as usize;
if ngap == 9 || ngap == 10 {
return 11;
}
if ngap < 1 {
return 1;
}
return ngap;
}
fn comb_sort(a: &mut Box<[f64]>) {
// previously: [f64]
let xlen = a.len();
let mut gap = xlen;
let mut swapped: bool;
let mut temp: f64;
loop {
swapped = false;
gap = new_gap(gap);
for i in 0..(xlen - gap) {
if a[i] > a[i + gap] {
swapped = true;
temp = a[i];
a[i] = a[i + gap];
a[i + gap] = temp;
}
}
if !(gap > 1 || swapped) {
break;
}
}
}
const N: usize = 10000000;
fn main() {
let mut arr: Box<[f64]> = Box::new([0.0; N]); // previously: [f64; N] = [0.0; N];
for z in 0..(N) {
arr[z] = (N - z) as f64;
}
comb_sort(&mut arr);
for z in 1..(N) {
if arr[z] < arr[z - 1] {
print!("!")
}
}
}
The output:
thread '<main>' has overflowed its stack
Illegal instruction (core dumped)
Or
thread 'main' has overflowed its stack
fatal runtime error: stack overflow
I know that my stack size is not enough, the same as C++ when creating a non-heap array that is too big inside a function, but this code is using heap but still shows stack overflow. What's really wrong with this code?
As far as I can tell, it seems like that code is still trying to allocate the array on the stack first, and then move it into the box after.
It works for me if I switch to Vec<f64> in place of Box<[f64]> like this:
fn new_gap(gap: usize) -> usize {
let ngap = ((gap as f64) / 1.3) as usize;
if ngap == 9 || ngap == 10 {
return 11;
}
if ngap < 1 {
return 1;
}
return ngap;
}
fn comb_sort(a: &mut [f64]) {
// previously: [f64]
let xlen = a.len();
let mut gap = xlen;
let mut swapped: bool;
let mut temp: f64;
loop {
swapped = false;
gap = new_gap(gap);
for i in 0..(xlen - gap) {
if a[i] > a[i + gap] {
swapped = true;
temp = a[i];
a[i] = a[i + gap];
a[i + gap] = temp;
}
}
if !(gap > 1 || swapped) {
break;
}
}
}
const N: usize = 10000000;
fn main() {
let mut arr: Vec<f64> = std::iter::repeat(0.0).take(N).collect();
//let mut arr: Box<[f64]> = Box::new([0.0; N]); // previously: [f64; N] = [0.0; N];
for z in 0..(N) {
arr[z] = (N - z) as f64;
}
comb_sort(arr.as_mut_slice());
for z in 1..(N) {
if arr[z] < arr[z - 1] {
print!("!")
}
}
}
In the future, the box syntax will be stabilized. When it is, it will support this large allocation, as no function call to Box::new will be needed, thus the array will never be placed on the stack. For example:
#![feature(box_syntax)]
fn main() {
let v = box [0i32; 5_000_000];
println!("{}", v[1_000_000])
}

Resources