use crate::standard_distributions::{standard_gamma, xorshift160_0_1_open};
use crate::{create_state, FDistribution};
impl FDistribution {
pub fn new(seeds: [u32; 8_usize]) -> Self {
let adjusted_seeds = crate::adjust_seeds!(seeds);
Self {
xyzuv_u_gamma_1: create_state(adjusted_seeds[0]),
xyzuv_n_0_gamma_1: create_state(adjusted_seeds[1]),
xyzuv_n_1_gamma_1: create_state(adjusted_seeds[2]),
xyzuv_uniform_1: create_state(adjusted_seeds[3]),
degree_of_freedom_1: 1_f64,
xyzuv_u_gamma_2: create_state(adjusted_seeds[4]),
xyzuv_n_0_gamma_2: create_state(adjusted_seeds[5]),
xyzuv_n_1_gamma_2: create_state(adjusted_seeds[6]),
xyzuv_uniform_2: create_state(adjusted_seeds[7]),
degree_of_freedom_2: 1_f64,
}
}
pub fn sample(&mut self) -> f64 {
let chi_1 = if self.degree_of_freedom_1 > 1_f64 {
standard_gamma(
&mut self.xyzuv_u_gamma_1,
&mut self.xyzuv_n_0_gamma_1,
&mut self.xyzuv_n_1_gamma_1,
&self.degree_of_freedom_1,
) * 2_f64
} else {
let y = standard_gamma(
&mut self.xyzuv_u_gamma_1,
&mut self.xyzuv_n_0_gamma_1,
&mut self.xyzuv_n_1_gamma_1,
&(3_f64 / 2_f64),
) * 2_f64;
let u = xorshift160_0_1_open(&mut self.xyzuv_uniform_1);
u.powi(2) * y * 2_f64
};
let chi_2 = if self.degree_of_freedom_2 > 1_f64 {
standard_gamma(
&mut self.xyzuv_u_gamma_2,
&mut self.xyzuv_n_0_gamma_2,
&mut self.xyzuv_n_1_gamma_2,
&self.degree_of_freedom_2,
) * 2_f64
} else {
let y = standard_gamma(
&mut self.xyzuv_u_gamma_2,
&mut self.xyzuv_n_0_gamma_2,
&mut self.xyzuv_n_1_gamma_2,
&(3_f64 / 2_f64),
) * 2_f64;
let u = xorshift160_0_1_open(&mut self.xyzuv_uniform_2);
u.powi(2) * y * 2_f64
};
(self.degree_of_freedom_2 * chi_1) / (chi_2 * self.degree_of_freedom_1)
}
pub fn try_set_params(
&mut self,
degree_of_freedom_1: u64,
degree_of_freedom_2: u64,
) -> Result<(u64, u64), &str> {
if degree_of_freedom_1 < 1_u64 || degree_of_freedom_2 < 2_u64 {
Err("自由度は自然数である必要があります。確率変数のパラメータは前回の設定を維持します。")
} else {
self.degree_of_freedom_1 = degree_of_freedom_1 as f64;
self.degree_of_freedom_2 = degree_of_freedom_2 as f64;
Ok((degree_of_freedom_1, degree_of_freedom_2))
}
}
}
impl std::fmt::Display for FDistribution {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
writeln!(f, "構造体の型: {}", std::any::type_name::<Self>())?;
writeln!(f, "自由度 1: {}", self.degree_of_freedom_1 as u64)?;
writeln!(f, "自由度 2: {}", self.degree_of_freedom_2 as u64)?;
Ok(())
}
}