#floating-point #random #pseudo-random #float

floaters

generate floating-point numbers in various ways

6 releases (breaking)

0.5.0 Aug 4, 2024
0.4.0 Jul 14, 2024
0.3.2 Jun 25, 2024
0.2.0 Jun 15, 2024
0.1.0 May 14, 2024

#657 in Algorithms

Download history 2/week @ 2024-07-22 73/week @ 2024-07-29 46/week @ 2024-08-05 26/week @ 2024-09-16 44/week @ 2024-09-23 4/week @ 2024-09-30

563 downloads per month

MIT license

22KB
154 lines

Floaters

Create floating-point numbers pseudorandomly in several experimental ways. Not only the significand may be filled with pseudorandom bits, but also at least parts of the exponent, depending on the chosen method. If the exponent contains pseudorandom bits, the numbers will not be uniformly distributed. Those methods may be useful in some cases where you need a wider range of numbers, while equidistribution is not a priority. The sign bit may be pseudorandom as well, depending on the method.

The crate adds a trait for any type that implements Rng from rand_core.

In version 0.5.0 the re-export of rand_xoshiro was removed and a few more helper functions were added.

Examples

plot

The above chart was created with the following code:

use floaters::{NonCanonical, Sign};
use rand_xoshiro::rand_core::RngCore; // version = "0.6.0"
use rand_xoshiro::Xoshiro256PlusPlus;
use rand_seeder::Seeder; // version = "0.3.0"
use plotters::prelude::*; // version = "0.3.6"

fn main() -> Result<(), Box<dyn std::error::Error>> {

    let root = BitMapBackend::new("random_walk.png", (800, 600))
        .into_drawing_area();
    
    root.fill(&WHITE)?;

    let mut prng: Xoshiro256PlusPlus =
        Seeder::from("walk the line").make_rng();

    (0..1000).for_each(|_| { prng.next_u64(); } );

    let mut x: f64 = 50.0;

    let mut numbers = Vec::<f64>::with_capacity(100);

    (0..100).for_each(|_| {
        x += prng.with_params_f64(55, Sign::Signed);
        numbers.push(x);
    });

    let mut chart = ChartBuilder::on(&root)
        .caption("(pseudo)random walk",
            ("sans-serif", 30).into_font())
        .margin(5)
        .x_label_area_size(30)
        .y_label_area_size(30)
        .build_cartesian_2d(0f64..100f64, 40f64..60f64)?;

    chart.configure_mesh().draw()?;

    chart.draw_series(LineSeries::new(numbers
                                    .iter()
                                    .enumerate()
                                    .map(|x| (x.0 as f64, *x.1)),
                                        &RED,))?;

    root.present()?;

    Ok(())
}

A more basic example:

use rand_xoshiro::rand_core::{RngCore, SeedableRng};
use rand_xoshiro::Xoshiro256StarStar; // version = "0.6.0"
use floaters::NonCanonical;

fn main() {

    // Generate 5 pseudorandom f64 numbers with pseudorandom bits
    // also in the exponent. The numbers are not equidistributed,
    // but we get a wider range of values.
    
    let mut rng = Xoshiro256StarStar::from_entropy();
    
    println!("Numbers get closer to zero, \
             but are not equidistributed:");
    
    for _ in 0..5 { println!("{}", rng.noncanonical_f64()) }

    // Generate tuples of f32 numbers with a truly random seed.
    
    // Clock the PRNG several times without generating numbers.
    (0..512).for_each(|_| { rng.next_u64(); } );
    
    println!("\nSigned (f32, f32):");
    
    for _ in 0..5 { println!("{:?}", rng.signed_tuple_f32()); }

}

References

https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf

https://prng.di.unimi.it

https://mina86.com/2016/random-reals/

Dependencies

~310KB