Rust throwing error 'attempt to use a non-constant value in a constant' - random

I'm a rust newbie and I wanted to understand why Rust is throwing me an error when I run the following code:
let rng = rand::thread_rng();
const NUMBER_TO_GUESS: u32 = rng.gen();
Error:
error[E0435]: attempt to use a non-constant value in a constant
--> src/main.rs:12:34
|
12 | const NUMBER_TO_GUESS: u32 = rng.gen();
| --------------------- ^^^ non-constant value
| |
| help: consider using `let` instead of `const`: `let NUMBER_TO_GUESS`

If you really want a const (generated during compile time and does not change each time the program is run), then cargo add const-random and use the following:
use const_random::const_random;
fn main() {
const NUMBER_TO_GUESS: u32 = const_random!(u32);
println!("Hello {}", NUMBER_TO_GUESS);
}
I see that the variable is named NUMBER_TO_GUESS. A guessing game should probably change the number on each run, so you would use the following:
use rand::Rng;
fn main() {
// rng needs to be mut because it needs to be modified so that
// rng.gen() returns different values each time
let mut rng = rand::thread_rng();
let number_to_guess: u32 = rng.gen();
println!("Hello {}", number_to_guess);
}
I see in the comments you are from Javascript. Here is a table with some roughly corresponding syntax:
Typescript
Rust
let x: Something = y;
let mut x = y;
let x: Readonly<Something> = y;
let mut x = &y;
const x: Something = y;
let x = &mut y;
const x: Readonly<Something> = y;
let x = y;
Closest is Webpack's EnvironmentPlugin/DefinePlugin with const x: string = process.env.SOMETHING; plus a minifier
const x = "That thing";
In the Rust code you have, you see let rng before const NUMBER_TO_GUESS. The compiler does not see it this way. Ahead-of-time compiled languages always calculate the const one before other variables.

Related

Strange bug using Rust and ndarray

I have a very strange bug in my Rust code using ndarray. The following code runs with no error:
// ...other code before producing a lot of print on screen
//
let rank = 2;
let mut Q = Array2::<f64>::zeros((rank,rank));
// U is an Array2<F> where F is a struct that can call eval(&self,&f64) -> f64
for i in 0..rank {
println!("i = {}",i);
for j in 0..rank {
let v: f64 = U[[0,i]].eval(&1.0);
println!("i,j = {}-{} -- v = {}",i,j,v);
Q[[i,j]] = v;
}
}
but if I change the order of the indices for writing to a specific entry of the matrix Q, like for example
for i in 0..rank {
println!("i = {}",i);
for j in 0..rank {
let v: f64 = U[[0,i]].eval(&1.0);
println!("i,j = {}-{} -- v = {}",i,j,v);
Q[[j,i]] = v;
}
}
the executable runs forever, without printing anything on the screen (neither the output that is supposed to be produced before that point).
I've tried to replace the line
let v: f64 = U[[0,i]].eval(&1.0);
with
let v: f64 = f64::sin(1.0);
and now both version works fine.
Do you have any idea how to debug such kind of situation?

How to seed the Random Number generator in Rust with a string or a number

I need to seed the Random Number generator in Rust to get deterministic output.
I am using the following to generate a random number:
let mut rng = rand::thread_rng();
let mut random_number = rng.gen_range(0.0..1.0);
How do I seed this with
String; and a
Number
Use the rand_pcg crate with rand_pcg = "0.3.1" in your Cargo.toml:
use rand_pcg::Pcg32;
use rand::{Rng, SeedableRng, rngs::StdRng};
let mut rng = Pcg32::seed_from_u64(42);
let random_number: u32 = rng.gen_range(0..100);
println!("{}", random_number);

VirtualFree results in ERROR_INVALID_PARAMETER in Rust

Here's a situation. I'm allocating memory using the following function
let addr = windows::Win32::System::Memory::VirtualAlloc(
ptr::null_mut(),
size,
windows::Win32::System::Memory::MEM_RESERVE | windows::Win32::System::Memory::MEM_COMMIT,
windows::Win32::System::Memory::PAGE_READWRITE,
);
Upon successful allocation, the resulting memory is cast to *mut u8 and everyone's happy until it's a time to deallocate this same space. Here's how I approach it
let result = System::Memory::VirtualFree(
ptr as *mut c_void,
size,
windows::Win32::System::Memory::MEM_DECOMMIT).0;
In Win32 API docs stated that upon successful reclamation of memory VirtualFree spits out a non-zero value, but in my case the return value turns out to be a zero. I was quite dismayed at first, so I decided to get right into the weeds to further investigate the problem. During my investigation I found out that calling GetLastError would give me a more detailed explanation of what I might have done wrong. The value this function ended up returning was 0x57, i.e ERROR_INVALID_PARAMETER. As that issue has been a primary source of majority of negative emotions for quite a while, I've had a lot of time to experiment with input values to these precious functions. And here's a thing. The setting I started describing the problem with functions perfectly when I'm running tests in release mode, but is completely off the table when it comes to debug mode. When I pass 0 as a second argument to VirtualFree, and MEM_RELEASE as a third one, it ends up crashing in both modes. So, how do I escape this nightmare and finally resolve the issue?
UPD
I apologize for the lack of context. So, the problem occurs when I'm running the following test
#[test]
fn stress() {
let mut rng = rand::thread_rng();
let seed: u64 = rng.gen();
let seed = seed % 10000;
run_stress(seed);
}
fn run_stress(seed: u64) {
let mut a = Dlmalloc::new();
println!("++++++++++++++++++++++ seed = {}\n", seed);
let mut rng = StdRng::seed_from_u64(seed);
let mut ptrs = Vec::new();
let max = if cfg!(test_lots) { 1_000_000 } else { 10_000 };
unsafe {
for _k in 0..max {
let free = !ptrs.is_empty()
&& ((ptrs.len() < 10_000 && rng.gen_bool(1f64 / 3f64)) || rng.gen());
if free {
let idx = rng.gen_range(0, ptrs.len());
let (ptr, size, align) = ptrs.swap_remove(idx);
println!("ptr: {:p}, size = {}", ptr, size);
a.free(ptr, size, align); // crashes right after the call to this function
continue;
}
if !ptrs.is_empty() && rng.gen_bool(1f64 / 100f64) {
let idx = rng.gen_range(0, ptrs.len());
let (ptr, size, align) = ptrs.swap_remove(idx);
let new_size = if rng.gen() {
rng.gen_range(size, size * 2)
} else if size > 10 {
rng.gen_range(size / 2, size)
} else {
continue;
};
let mut tmp = Vec::new();
for i in 0..cmp::min(size, new_size) {
tmp.push(*ptr.add(i));
}
let ptr = a.realloc(ptr, size, align, new_size);
assert!(!ptr.is_null());
for (i, byte) in tmp.iter().enumerate() {
assert_eq!(*byte, *ptr.add(i));
}
ptrs.push((ptr, new_size, align));
}
let size = if rng.gen() {
rng.gen_range(1, 128)
} else {
rng.gen_range(1, 128 * 1024)
};
let align = if rng.gen_bool(1f64 / 10f64) {
1 << rng.gen_range(3, 8)
} else {
8
};
let zero = rng.gen_bool(1f64 / 50f64);
let ptr = if zero {
a.calloc(size, align)
} else {
a.malloc(size, align)
};
for i in 0..size {
if zero {
assert_eq!(*ptr.add(i), 0);
}
*ptr.add(i) = 0xce;
}
ptrs.push((ptr, size, align));
}
}
}
I should point out that it doesn't crash on a particular iteration -- this number always changes.
This is the excerpt from the dlmalloc-rust crate.
The crate I'm using for interacting with winapi is windows-rs
Here's an implementation of free
pub unsafe fn free(ptr: *mut u8, size: usize) -> bool {
let result = System::Memory::VirtualFree(
ptr as *mut c_void,
0,
windows::Win32::System::Memory::MEM_RELEASE).0;
if result == 0 {
let cause = windows::Win32::Foundation::GetLastError().0;
dlverbose!("{}", cause);
}
result != 0
}

Rust - why is my program performing very slowly - over 5 times slower than the same program written in JavaScript using Node

I have finished converting an application that I made in JavaScript to Rust for increased performance. I am learning to program, and all the application does is work out the multiplicative persistence of any number in a range. It multiplies all digits together to form a new number, then repeats until the number becomes less than 10.
My issue is, my program written in JavaScript is over 5 times faster than the same in Rust. I must be doing something wrong with converting Strings to ints somewhere, I even tried swapping i128 to i64 and it made little difference.
If I run "cargo run --release" it is still slower!
Please can somebody look through my code to work out if there is any part of it that is causing the issues? Thank you in advance :)
fn multiplicative_persistence(mut user_input: i128) -> i128 {
let mut steps: i128 = 0;
let mut numbers: Vec<i128> = Vec::new();
while user_input > 10 {
let string_number: String = user_input.to_string();
let digits: Vec<&str> = string_number.split("").collect();
let mut sum: i128 = 1;
let digits_count = digits.len();
for number in 1..digits_count - 1 {
sum *= digits[number].parse::<i128>().unwrap();
}
numbers.push(sum);
steps += 1;
user_input = sum;
}
return steps;
}
fn main() {
// let _user_input: i128 = 277777788888899;
let mut highest_steps_count: i128 = 0;
let mut highest_steps_number: i128 = 0;
let start: i128 = 77551000000;
let finish: i128 = 1000000000000000;
for number in start..=finish {
// println!("{}: {}", number, multiplicative_persistence(number));
if multiplicative_persistence(number) > highest_steps_count {
highest_steps_count = multiplicative_persistence(number);
highest_steps_number = number;
}
if number % 1000000 == 0 {
println!("Upto {} so far: {}", number, highest_steps_number);
}
}
println!("Highest step count: {} at {}", highest_steps_number, highest_steps_count);
}
I do plan to use the numbers variable in the function but I have not learnt enough to know how to properly return it as an associative array.
Maybe the issue is that converting a number to a string, and then re-converting it again into a number is not that fast, and avoidable. You don't need this intermediate step:
fn step(mut x: i128) -> i128 {
let mut result = 1;
while x > 0 {
result *= x % 10;
x /= 10;
}
result
}
fn multiplicative_persistence(mut user_input: i128) -> i128 {
let mut steps = 0;
while user_input > 10 {
user_input = step(user_input);
steps += 1;
}
steps
}
EDIT Just out of curiosity, I'd like to know whether the bottleneck is really due to the string conversion or to the rest of the code that is somehow wasteful. Here is an example that does not call .split(""), does not re-allocate that intermediate vector, and only allocates once, not at each step, the string.
#![feature(fmt_internals)]
use std::fmt::{Formatter, Display};
fn multiplicative_persistence(user_input: i128) -> i128 {
let mut steps = 0;
let mut digits = user_input.to_string();
while user_input > 10 {
let product = digits
.chars()
.map(|x| x.to_digit(10).unwrap())
.fold(1, |acc, i| acc*i);
digits.clear();
let mut formatter = Formatter::new(&mut digits);
Display::fmt(&product, &mut formatter).unwrap();
steps += 1;
}
steps
}
I have basically inlined the string conversion that would be performed by .to_string() in order to re-use the already-allocated buffer, instead of re-allocating one each iteration. You can try it out on the playground. Note that you need a nightly compiler because it makes use of an unstable feature.

Why is what timers show so counter-intuitive?

I am making a parser of some text. I need to support unicode texts, that's why I am using the String::chars iterator:
playground
use std::time::Instant;
fn main() {
let text = "a".repeat(10000);
let mut timer1 = 0;
let mut timer2 = 0;
let start1 = Instant::now();
for pos in 1..10000 {
let start2 = Instant::now();
let ch = text.chars().nth(pos).unwrap();
timer2 += start2.elapsed().as_millis();
}
timer1 += start1.elapsed().as_millis();
println!("timer1: {} timer2: {}", timer1, timer2);
}
Example output:
timer1: 4276 timer2: 133
Why is timer2 unbelievably less than timer1, when I believe they should be very close to each other?
P.S. I know already that .nth is slow, and shouldn't be used.
You are running into a resolution problem. The inside of the loop takes (on average) less than one millisecond to execute, so start2.elapsed().as_millis() usually evaluates to 0. To fix this problem, you could do some operation inside the loop that takes even longer, or change your resolution from milliseconds to something smaller, like microseconds or nanoseconds.
switching to microseconds yields a more consistent time
use std::time::{Instant};
fn main() {
let text = "a".repeat(10000);
let mut timer1 = 0;
let mut timer2 = 0;
let start1 = Instant::now();
for pos in 1..10000 {
let start2 = Instant::now();
let ch = text.chars().nth(pos).unwrap();
timer2+=start2.elapsed().as_micros();
}
timer1+=start1.elapsed().as_micros();
println!("timer1: {} timer2: {}", timer1, timer2);
}
output
timer1: 3511812 timer2: 3499669
This question was tagged performance, so I'd like to point out that using std::Instant is a very tedious way to measure performance. Better ways include criterion.rs, flamegraph and cargo-bench.

Resources