Exclude value out of Rand gen_range - random

I would like to have a random number between -max and max where max is some i32 value, but I would like to exclude zero. I am using rand version 0.8.5.
I would like to have a code something like
let mut rng = rand::thread_rng();
rng.gen_range(-max..max);
But this code has zero included. Is there an idiomatic way to exclude it?

Related

How can you extend a collection in parallel?

I have a HashMap which I'd like to add elements to as fast as possible. I tried using par_extend, but it actually ended up being slower than the serial version. My guess is that it is evaluating the iterator in parallel, but extending the collection serially. Here's my code:
use std::collections::HashMap;
use rayon::prelude::*;
use time::Instant;
fn main() {
let n = 1e7 as i64;
// serial version
let mut t = Instant::now();
let mut m = HashMap::new();
m.extend((1..n).map(|i| (i, i)));
println!("Time in serial version: {}", t.elapsed().as_seconds_f64());
// parallel version - slower
t = Instant::now();
let mut m2 = HashMap::new();
m2.par_extend((1..n).into_par_iter().map(|i| (i, i)));
println!("Time in parallel version: {}", t.elapsed().as_seconds_f64());
}
Is there a faster way to extend a HashMap that actually adds the elements in parallel? Or a similar data structure that can be extended in parallel? I know this would run faster with something like an FnvHashMap, but it seems like it should also be possible to speed this up with parallelism. (and yes, I'm compiling with --release)

Is it possible to create an RNG using an arbitrary-length vector as a seed without creating an entire RNG implementation myself?

This code works fine for vectors of exact length 32 - however, if 32 is changed to some other number, such as 16 or 64, then there is a mismatched type error:
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::convert::TryInto;
fn generate_random(bytes: Vec<u8>) -> u32 {
let bytes: [u8; 32] = bytes.try_into().unwrap();
let mut seeded_rng = StdRng::from_seed(bytes);
seeded_rng.gen_range(0..32)
}
The rand docs include an example for implementing SeedableRng for RNGs with large seeds, however this is not a complete working example and requires implementing the rest of the RNG (i.e. traits Rng and RngCore) for a working solution.
Is it possible to create an RNG using an arbitrary-length vector as a seed without creating an entire RNG implementation myself, and if so, how do I go about doing this?
I have found a solution which involves using the OpenSSL crate to first make a hash of the N-length vector, then use the resulting hash as the random seed:
use openssl::sha::Sha256;
use rand::{rngs::StdRng, Rng, SeedableRng};
fn generate_random(bytes: Vec<u8>) -> u32 {
let mut sha256 = Sha256::new();
sha256.update(&bytes);
let hash = sha256.finish();
let mut seeded_rng = StdRng::from_seed(hash);
seeded_rng.gen_range(0..32)
}
Although the true entropy is still 32 bytes using this method, it ensures that any change to part of the seed bytes causes a different resulting RNG, unlike truncating the vector.
Any hash function which takes an arbitrary length u8 slice and returns a 32-byte u8 array could also work in place of openssl::sha::Sha256.

How to generate a random Rust integer in a range without introducing bias?

How you I generate a random dice roll in Rust?
I know I can use rand::random, but that requires I want to generate a value of an integer type. Using rand::random<u8>() % 6 introduces a bias.
Use Rng::gen_range for a one-off value:
use rand::{self, Rng}; // 0.8.0
fn main() {
let mut rng = rand::thread_rng();
let die = rng.gen_range(1..=6);
println!("The die was: {}", die);
}
Under the hood, this creates a Uniform struct. Create this struct yourself if you will be getting multiple random numbers:
use rand::{
self,
distributions::{Distribution, Uniform},
}; // 0.8.0
fn main() {
let mut rng = rand::thread_rng();
let die_range = Uniform::new_inclusive(1, 6);
let die = die_range.sample(&mut rng);
println!("{}", die);
}
Uniform does some precomputation to figure out how to map the complete range of random values to your desired range without introducing bias. It translates and resizes your original range to most closely match the range of the random number generator, discards any random numbers that fall outside this new range, then resizes and translates back to the original range.
See also:
Why do people say there is modulo bias when using a random number generator?
You're correct that a bias is introduced; whenever you want to map from set A to set B where the cardinality of set B is not a factor or multiple of set A, you will have bias.
In your case, 42*6=252. So you can just throw away any u8 values of 252 or greater (and call random again).
Your output can then be safely mapped with the modulus operator. Finally add 1 to achieve the standard [1,6] dice output.
It might seem unclean to call random again but there is no way of mapping a set of 256 values to a set of 6 without introducing bias.
Edit: looks like the rand crate has something which takes bias into account: https://docs.rs/rand/latest/rand/distributions/uniform/struct.Uniform.html

Halide: How to deal with Expr evaluated as nan or inf?

I have a 1D Func over which I'd like to perform the following: take the sum of a kernel of n values, and divide it by the sum of the kernel shifted by 1. Here's the code I have so far:
Var x("x");
Func result("result");
RDom r(0, kernel_size);
Expr sum1 = sum(vec_func(x+r));
Expr sum2 = sum(vec_func(x+r+1));
Expr quotient = sum1 / sum2;
result(x) = quotient;
This is an example of the type of calculation which might result in a NaN or Inf. Ideally I would be able to deal with this in Halide using something like this:
Expr safe_calc = select(isnan(quotient) || isinf(quotient), 0, quotient);
result(x) = quotient;
Does such a method exist in Halide?
Expr Halide::is_nan(Expr) exists right now, but we are missing is_finite. (Added as https://github.com/halide/Halide/issues/2497)
However: be aware that Halide does floating point math in accordance with -ffast-math rules, which means it is allowed to optimize the code in ways that assume NaN/Inf values can't happen. If it's possible to structure your code in a way to ensure such values aren't possible, you should do so.

generate random letter and fixed number combination

I need to generate a random sequence of a single letter and 6 digit combination, example: F841257
I was looking into rand crate, but something doesn't quite work.
extern crate rand;
fn main() {
println!("{:?}", rand::random::<char>());
}
prints something like '\u{6ae02}' and println!("{}", rand::random::<char>()); produces some weird glyph.
Can someone point me in the right direction of how I could achieve this?
First, a working program:
extern crate rand;
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
let letter: char = rng.gen_range(b'A', b'Z') as char;
let number: u32 = rng.gen_range(0, 999999);
let s = format!("{}{:06}", letter, number);
println!("{}", s);
}
Next, an explanation.
rand::random::<char>() returns a random value from the whole char range, that is, it may return arbitrary Unicode code point. That's why you see weird glyphs - these are likely values from upper Unicode planes.
You need to define boundaries of what you need to generate. First, you need a letter, then you need six digits. A letter is any character between 'A' and 'Z', and six digits can be represented by a number from 0 to 999999 which is padded with zeros when printing.
So, first, we generate a u8 which corresponds to a letter in ASCII and convert it to char (unfortunately, rand crate does not provide range distribution for chars, so we have to use such indirection).
Second, we generate a u32 between 0 and 999999.
Then we print them in the desired format. Here are a few values which this program generates: V285490, Y865809, A704620.

Resources