fixes and a PRNG
This commit is contained in:
parent
b4c2e5ea9b
commit
2d6b61b6cf
9 changed files with 336 additions and 203 deletions
|
|
@ -1,67 +1,57 @@
|
|||
/// Pi randomness test
|
||||
/// Uses a Monte Carlo simulation to estimate randomness by calculating the approximation of Pi.
|
||||
|
||||
use statrs::distribution::{Normal, ContinuousCDF};
|
||||
|
||||
use crate::Onod;
|
||||
|
||||
impl Onod {
|
||||
|
||||
/// Pi randomness test
|
||||
/// Uses a Monte Carlo simulation to estimate randomness by calculating the approximation of Pi.
|
||||
/// This implementation of the Pi randomness test closely follows the logic of the original Java implementation.
|
||||
/// However, minor differences in the results may arise due to the following reasons:
|
||||
///
|
||||
/// 1. **Floating-Point Precision**:
|
||||
/// Rust and Java both use 64-bit floating-point numbers (`double` in Java, `f64` in Rust), but slight differences
|
||||
/// in their implementations (e.g., rounding modes, intermediate representations) can lead to small deviations.
|
||||
///
|
||||
/// 2. **Math Libraries**:
|
||||
/// Java uses Apache Commons Math for statistical computations, which may implement certain calculations
|
||||
/// (e.g., Z-scores and normal distribution CDFs) differently compared to the `statrs` crate used in Rust.
|
||||
///
|
||||
/// 3. **Bit Accuracy**:
|
||||
/// The Java implementation notes the significance of bit accuracy in floating-point computations,
|
||||
/// as defined in the IEEE 754 standard. Differences in handling edge cases (e.g., subnormal values,
|
||||
/// precision limits) could lead to slight variations.
|
||||
///
|
||||
/// These differences are generally negligible for practical purposes and do not affect the overall functionality or
|
||||
/// statistical significance of the test.
|
||||
/// Pi randomness test using nalgebra for vectorized operations.
|
||||
pub fn pi(samples: &[u8]) -> (f64, f64, f64) {
|
||||
if samples.len() < 4 {
|
||||
return (-1.0, 0.0, 1.0); // Not enough data
|
||||
}
|
||||
|
||||
if samples.is_empty() {
|
||||
let normalized_samples: Vec<f32> = get_floats(samples);
|
||||
|
||||
if normalized_samples.is_empty() {
|
||||
return (-1.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// Normalize samples to [0.0, 1.0)
|
||||
let normalized_samples: Vec<f64> = samples.iter().map(|&x| x as f64 / 255.0).collect();
|
||||
|
||||
// Initialize variables for summary statistics
|
||||
let mut sum_y = 0.0;
|
||||
let mut count = 0.0;
|
||||
let count = normalized_samples.len() as f64;
|
||||
|
||||
// Compute y-values (sqrt(1 - x^2)) and update summary statistics
|
||||
for &x in &normalized_samples {
|
||||
let y = (1.0 - x * x).sqrt();
|
||||
sum_y += y;
|
||||
count += 1.0;
|
||||
let y = (1.0 - x.powi(2)).sqrt();
|
||||
sum_y += y as f64;
|
||||
}
|
||||
|
||||
// Calculate mean of y-values
|
||||
let mean_y = sum_y / count;
|
||||
|
||||
// Calculate the test statistic
|
||||
let test_statistic = 4.0 * mean_y;
|
||||
|
||||
// Calculate variance and standard deviation
|
||||
let variance = (16.0 / count) * ((2.0 / 3.0) - (std::f64::consts::PI / 4.0).powi(2));
|
||||
let variance = compute_variance(count);
|
||||
let std_dev = variance.sqrt();
|
||||
|
||||
// Calculate Z-score
|
||||
let z_score = (test_statistic - std::f64::consts::PI) / std_dev;
|
||||
|
||||
// Use normal distribution to calculate p-value
|
||||
let normal_dist = Normal::new(0.0, 1.0).expect("Failed to create Normal distribution");
|
||||
let p_value = 2.0 * (1.0 - normal_dist.cdf(z_score.abs()));
|
||||
|
||||
(test_statistic, z_score, p_value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn get_floats(samples: &[u8]) -> Vec<f32> {
|
||||
let mut floats = Vec::new();
|
||||
for chunk in samples.chunks_exact(4) {
|
||||
let int_val = i32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
|
||||
let unsigned_val = (int_val as u32) >> 1; // Discard sign bit
|
||||
let normalized = unsigned_val as f32 / i32::MAX as f32;
|
||||
floats.push(normalized);
|
||||
}
|
||||
floats
|
||||
}
|
||||
|
||||
fn compute_variance(n: f64) -> f64 {
|
||||
let term = (2.0 / 3.0) - (std::f64::consts::PI / 4.0).powi(2);
|
||||
(16.0 / n) * term
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue