Skip to content

Commit

Permalink
Add partial math::rand implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
gtrafimenkov committed Oct 21, 2023
1 parent d2224ff commit ee45683
Show file tree
Hide file tree
Showing 19 changed files with 3,390 additions and 5 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target
/*.png
/Cargo.lock
/goexamples/flate-speed/flate-speed
/target
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ corresponding Go examples in [goexamples](./goexamples) folder.
- compress::zlib
- crypto
- crypto::md5
- crypto::sha1
- crypto::sha256
- encoding
- encoding::base64
Expand All @@ -61,6 +62,7 @@ corresponding Go examples in [goexamples](./goexamples) folder.
- io
- math
- math::bits
- math::rand
- os
- os::user
- strconv
Expand Down
127 changes: 127 additions & 0 deletions examples/mathrand.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use ggstd::image::{self, color, png, Image};
use ggstd::math::rand;

fn main() {
println!("global rand without seed:");
println!("{:x}", rand::int());
println!("{:x}", rand::int());
println!("{:x}", rand::int());
println!("{:x}", rand::int());

#[allow(deprecated)]
rand::seed(1);

println!();
println!("global rand with seed(1):");
println!("{:x}", rand::int());
println!("{:x}", rand::int());
println!("{:x}", rand::int());
println!("{:x}", rand::int());

println!();
println!("rand::Rand::new(rand::new_source(1)):");
let mut r = rand::Rand::new(rand::new_source(1));
println!("{:x}", r.int());
println!("{:x}", r.int());
println!("{:x}", r.int());
println!("{:x}", r.int());

println!();
println!("global rand::float64:");
println!("{}", rand::float64());
println!("{}", rand::float64());
println!("{}", rand::float64());
println!("{}", rand::float64());

println!();
println!("global rand::norm_float64:");
println!("{}", rand::norm_float64());
println!("{}", rand::norm_float64());
println!("{}", rand::norm_float64());
println!("{}", rand::norm_float64());

// create 3 png images with random dot placements
for seq in 0..3 {
random_dots_png(seq);
}

// showing that random numbers are uniformely distributed
uniformity_ints_png();
uniformity_floats_png();

// unless we want normal distribution
normal_distr_floats_png();
}

fn uniformity_ints_png() {
let width = 1000;
let samples = 100000;
let mut counters = vec![0_usize; width];
for _ in 0..samples {
let x = rand::intn(width as isize) as usize;
counters[x] += 1;
}
save_counters_to_png(width, width / 4, &counters, "uniform-ints.png");
}

fn uniformity_floats_png() {
let width = 1000;
let samples = 100000;
let mut counters = vec![0_usize; width];
for _ in 0..samples {
let x = (rand::float32() * width as f32) as usize;
counters[x] += 1;
}
save_counters_to_png(width, width / 4, &counters, "uniform-floats.png");
}

fn normal_distr_floats_png() {
let width = 1000;
let samples = 400000;
let mut counters = vec![0_usize; width];
for _ in 0..samples {
let x = (rand::norm_float64() * width as f64 / 3.0 + width as f64) / 2.0;
if x >= 0.0 && x < width as f64 {
counters[x as usize] += 1;
}
}
save_counters_to_png(width, width, &counters, "normal-distr-floats.png");
}

fn save_counters_to_png(width: usize, height: usize, counters: &[usize], file_name: &str) {
let mut img = white_image(width, height);
for x in 0..width {
img.set(
x as isize,
height as isize - counters[x] as isize,
&color::BLACK,
);
}
let mut f = std::fs::File::create(file_name).unwrap();
png::encode(&mut f, &img).unwrap();
}

fn random_dots_png(number: usize) {
let size = 500;
let count = 5000;
let mut img = white_image(size, size);
for _ in 0..count {
img.set(
rand::intn(size as isize),
rand::intn(size as isize),
&color::BLACK,
);
}
let mut f = std::fs::File::create(format!("random-dots-{:02}.png", number)).unwrap();
png::encode(&mut f, &img).unwrap();
}

fn white_image(width: usize, height: usize) -> image::Img {
let mut img = image::Img::new_nrgba(&image::rect(0, 0, width as isize, height as isize));
for y in 0..height {
for x in 0..width {
img.set(x as isize, y as isize, &color::WHITE);
}
}
img
}
3 changes: 3 additions & 0 deletions goexamples/mathrand/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module rust-ggstd/goexamples/mathrand

go 1.20
29 changes: 29 additions & 0 deletions goexamples/mathrand/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package main

import (
"fmt"
"math/rand"
)

func main() {
rand.Seed(1)
fmt.Println("global rand with seed(1):")
fmt.Printf("%x\n", rand.Int())
fmt.Printf("%x\n", rand.Int())
fmt.Printf("%x\n", rand.Int())
fmt.Printf("%x\n", rand.Int())

fmt.Println()
fmt.Println("global rand::Float64:")
fmt.Printf("%v\n", rand.Float64())
fmt.Printf("%v\n", rand.Float64())
fmt.Printf("%v\n", rand.Float64())
fmt.Printf("%v\n", rand.Float64())

fmt.Println()
fmt.Println("global rand.NormFloat64:")
fmt.Printf("%v\n", rand.NormFloat64()*1000)
fmt.Printf("%v\n", rand.NormFloat64())
fmt.Printf("%v\n", rand.NormFloat64())
fmt.Printf("%v\n", rand.NormFloat64())
}
7 changes: 3 additions & 4 deletions src/compress/flate/deflate_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use super::inflate;
use super::token::Token;
use crate::bytes;
use crate::io as ggio;
use crate::math::rand;
use std::io::Write;

struct DeflateTest<'a> {
Expand Down Expand Up @@ -1116,12 +1117,10 @@ fn test_best_speed_shift_offsets() {

// testData may not generate internal matches.
let mut test_data: Vec<u8> = vec![0; 32];
// ggrust TODO: use rand when implemented
// let rng = rand.New(rand.NewSource(0));
let mut rng = rand::Rand::new(rand::new_source(1));
#[allow(clippy::needless_range_loop)]
for i in 0..test_data.len() {
// testData[i] = byte(rng.Uint32())
test_data[i] = i as u8;
test_data[i] = rng.uint32() as u8;
}

// Encode the testdata with clean state.
Expand Down
1 change: 1 addition & 0 deletions src/math/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod bits;
pub mod rand;
40 changes: 40 additions & 0 deletions src/math/rand/auto_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// // Copyright 2022 The Go Authors. All rights reserved.
// // Use of this source code is governed by a BSD-style
// // license that can be found in the LICENSE file.

// package rand_test

// import (
// . "math/rand"
// "testing"
// )

// // This test is first, in its own file with an alphabetically early name,
// // to try to make sure that it runs early. It has the best chance of
// // detecting deterministic seeding if it's the first test that runs.

// func TestAuto(t *testing.T) {
// // Pull out 10 int64s from the global source
// // and then check that they don't appear in that
// // order in the deterministic Seed(1) result.
// var out []int64
// for i := 0; i < 10; i++ {
// out = append(out, Int63())
// }

// // Look for out in Seed(1)'s output.
// // Strictly speaking, we should look for them in order,
// // but this is good enough and not significantly more
// // likely to have a false positive.
// Seed(1)
// found := 0
// for i := 0; i < 1000; i++ {
// x := Int63()
// if x == out[found] {
// found++
// if found == len(out) {
// t.Fatalf("found unseeded output in Seed(1) output")
// }
// }
// }
// }
133 changes: 133 additions & 0 deletions src/math/rand/example_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// // Copyright 2012 The Go Authors. All rights reserved.
// // Use of this source code is governed by a BSD-style
// // license that can be found in the LICENSE file.

// package rand_test

// import (
// "fmt"
// "math/rand"
// "os"
// "strings"
// "text/tabwriter"
// )

// // These tests serve as an example but also make sure we don't change
// // the output of the random number generator when given a fixed seed.

// func Example() {
// answers := []string{
// "It is certain",
// "It is decidedly so",
// "Without a doubt",
// "Yes definitely",
// "You may rely on it",
// "As I see it yes",
// "Most likely",
// "Outlook good",
// "Yes",
// "Signs point to yes",
// "Reply hazy try again",
// "Ask again later",
// "Better not tell you now",
// "Cannot predict now",
// "Concentrate and ask again",
// "Don't count on it",
// "My reply is no",
// "My sources say no",
// "Outlook not so good",
// "Very doubtful",
// }
// fmt.Println("Magic 8-Ball says:", answers[rand.Intn(len(answers))])
// }

// // This example shows the use of each of the methods on a *Rand.
// // The use of the global functions is the same, without the receiver.
// func Example_rand() {
// // Create and seed the generator.
// // Typically a non-fixed seed should be used, such as time.Now().UnixNano().
// // Using a fixed seed will produce the same output on every run.
// r := rand.New(rand.NewSource(99))

// // The tabwriter here helps us generate aligned output.
// w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
// defer w.Flush()
// show := func(name string, v1, v2, v3 any) {
// fmt.Fprintf(w, "%s\t%v\t%v\t%v\n", name, v1, v2, v3)
// }

// // Float32 and Float64 values are in [0, 1).
// show("Float32", r.Float32(), r.Float32(), r.Float32())
// show("Float64", r.Float64(), r.Float64(), r.Float64())

// // ExpFloat64 values have an average of 1 but decay exponentially.
// show("ExpFloat64", r.ExpFloat64(), r.ExpFloat64(), r.ExpFloat64())

// // norm_float64 values have an average of 0 and a standard deviation of 1.
// show("norm_float64", r.norm_float64(), r.norm_float64(), r.norm_float64())

// // Int31, Int63, and Uint32 generate values of the given width.
// // The Int method (not shown) is like either Int31 or Int63
// // depending on the size of 'int'.
// show("Int31", r.Int31(), r.Int31(), r.Int31())
// show("Int63", r.Int63(), r.Int63(), r.Int63())
// show("Uint32", r.Uint32(), r.Uint32(), r.Uint32())

// // Intn, Int31n, and Int63n limit their output to be < n.
// // They do so more carefully than using r.Int()%n.
// show("Intn(10)", r.Intn(10), r.Intn(10), r.Intn(10))
// show("Int31n(10)", r.Int31n(10), r.Int31n(10), r.Int31n(10))
// show("Int63n(10)", r.Int63n(10), r.Int63n(10), r.Int63n(10))

// // Perm generates a random permutation of the numbers [0, n).
// show("Perm", r.Perm(5), r.Perm(5), r.Perm(5))
// // Output:
// // Float32 0.2635776 0.6358173 0.6718283
// // Float64 0.628605430454327 0.4504798828572669 0.9562755949377957
// // ExpFloat64 0.3362240648200941 1.4256072328483647 0.24354758816173044
// // norm_float64 0.17233959114940064 1.577014951434847 0.04259129641113857
// // Int31 1501292890 1486668269 182840835
// // Int63 3546343826724305832 5724354148158589552 5239846799706671610
// // Uint32 2760229429 296659907 1922395059
// // Intn(10) 1 2 5
// // Int31n(10) 4 7 8
// // Int63n(10) 7 6 3
// // Perm [1 4 2 3 0] [4 2 1 3 0] [1 2 4 0 3]
// }

// func ExamplePerm() {
// for _, value := range rand.Perm(3) {
// fmt.Println(value)
// }

// // Unordered output: 1
// // 2
// // 0
// }

// func ExampleShuffle() {
// words := strings.Fields("ink runs from the corners of my mouth")
// rand.Shuffle(len(words), func(i, j int) {
// words[i], words[j] = words[j], words[i]
// })
// fmt.Println(words)
// }

// func ExampleShuffle_slicesInUnison() {
// numbers := []byte("12345")
// letters := []byte("ABCDE")
// // Shuffle numbers, swapping corresponding entries in letters at the same time.
// rand.Shuffle(len(numbers), func(i, j int) {
// numbers[i], numbers[j] = numbers[j], numbers[i]
// letters[i], letters[j] = letters[j], letters[i]
// })
// for i := range numbers {
// fmt.Printf("%c: %c\n", letters[i], numbers[i])
// }
// }

// func ExampleIntn() {
// fmt.Println(rand.Intn(100))
// fmt.Println(rand.Intn(100))
// fmt.Println(rand.Intn(100))
// }
Loading

0 comments on commit ee45683

Please sign in to comment.