Reputation: 63
Trying to generate a random number from the Standard Normal distribution. Need to multiply the value by 0.1 to get the number range i'm looking for. I tried using the documentation from rand_dist you can find here: https://docs.rs/rand_distr/0.3.0/rand_distr/struct.StandardNormal.html
My Cargo.toml is the following:
[package]
name = "test_rng"
version = "0.1.0"
authors = ["Jack"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.7.3"
rand_distr = "0.3.0"
The starting rust code is the example provided in the rand_dist docs from above:
use rand::prelude::*;
use rand_distr::StandardNormal;
fn main() {
let val: f64 = thread_rng().sample(StandardNormal);
println!("{}", val);
}
When I run this it works as expected and the output is:
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
Finished dev [unoptimized + debuginfo] target(s) in 2.11s
Running `target\debug\test_rng.exe`
0.48398855288705356
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
This is where I'm hitting an issue, when I try to multiply the number by 0.1 in the following code I get the resulting error:
fn main() {
let val: f64 = 0.1 * thread_rng().sample(StandardNormal);
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
error[E0284]: type annotations needed: cannot satisfy `<f64 as std::ops::Mul<_>>::Output == f64`
--> src\main.rs:5:24
|
5 | let val: f64 = 0.1 * thread_rng().sample(StandardNormal);
| ^ cannot satisfy `<f64 as std::ops::Mul<_>>::Output == f64`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0284`.
error: could not compile `test_rng`.
To learn more, run the command again with --verbose.
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
I tried to change 0.1 to 0.1_f64 but that gave the same error.
I tried to convert random number to f64 (which it should already be) with as f64
but that resulted in the following:
fn main() {
let val: f64 = 0.1 * thread_rng().sample(StandardNormal) as f64;
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
error[E0282]: type annotations needed
--> src\main.rs:5:39
|
5 | let val: f64 = 0.1 * thread_rng().sample(StandardNormal) as f64;
| ^^^^^^ cannot infer type for type parameter `T` declared on the associated function `sample`
|
= note: type must be known at this point
help: consider specifying the type arguments in the method call
|
5 | let val: f64 = 0.1 * thread_rng().sample::<T, D>(StandardNormal) as f64;
| ^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0282`.
error: could not compile `test_rng`.
To learn more, run the command again with --verbose.
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
Thought it was a precedence issue so I tried wrapping second half in parenthesis but got the same error.
I can get it to work by making the variable mutable and separating the line into two operations like the following:
fn main() {
let mut val: f64 = thread_rng().sample(StandardNormal);
val *= 0.1;
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
Finished dev [unoptimized + debuginfo] target(s) in 1.62s
Running `target\debug\test_rng.exe`
-0.034993448117065
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
Any idea what is going on with the multiplication of the f64 with the output of the random number?
Upvotes: 6
Views: 3703
Reputation: 2016
You can use the following:
fn main() {
let val: f64 = 0.1 * thread_rng().sample::<f64,_>(StandardNormal);
println!("{}", val);
}
This explicitly forces the sample function to return a f64. What was likely going on is that the rust type inference doesn't realize that the RHS needs to be f64, though I'm not sure exactly why.
Edit:
I think some the blame here goes to the definition of sample
, in that it uses an unrestricted type parameter. An MVE for this would be:
pub trait Marker{}
impl Marker for f64{}
impl Marker for f32{}
fn does_not_work<T>() -> T{
unimplemented!()
}
fn does_work<T: Marker>() -> T{
unimplemented!()
}
fn main() {
let val: f64 = 0.1 * does_work();
let val: f64 = 0.1 * does_not_work();
}
It's somewhat understandable that the compiler can't infer types for does_not_work
, b/c how is it meant to know about every possible type that could multiply with f64
? However of we restrict things to only certain types with a trait, then the list of possible types becomes finite and type inference works again.
Upvotes: 4