use crate::core_type::D38;
const SCALE_REF: u32 = 37;
include!(concat!(env!("OUT_DIR"), "/wide_consts.rs"));
const PI_RAW_S37: i128 = match i128::from_str_radix(PI_D38_S37, 10) {
Ok(v) => v,
Err(_) => panic!("consts: PI_D38_S37 not parseable"),
};
const TAU_RAW_S37: i128 = match i128::from_str_radix(TAU_D38_S37, 10) {
Ok(v) => v,
Err(_) => panic!("consts: TAU_D38_S37 not parseable"),
};
const HALF_PI_RAW_S37: i128 = match i128::from_str_radix(HALF_PI_D38_S37, 10) {
Ok(v) => v,
Err(_) => panic!("consts: HALF_PI_D38_S37 not parseable"),
};
const QUARTER_PI_RAW_S37: i128 = match i128::from_str_radix(QUARTER_PI_D38_S37, 10) {
Ok(v) => v,
Err(_) => panic!("consts: QUARTER_PI_D38_S37 not parseable"),
};
const E_RAW_S37: i128 = match i128::from_str_radix(E_D38_S37, 10) {
Ok(v) => v,
Err(_) => panic!("consts: E_D38_S37 not parseable"),
};
const GOLDEN_RAW_S37: i128 = match i128::from_str_radix(GOLDEN_D38_S37, 10) {
Ok(v) => v,
Err(_) => panic!("consts: GOLDEN_D38_S37 not parseable"),
};
pub trait DecimalConsts: Sized {
fn pi() -> Self;
fn tau() -> Self;
fn half_pi() -> Self;
fn quarter_pi() -> Self;
fn golden() -> Self;
fn e() -> Self;
}
pub(crate) fn pi_at_target<const TARGET: u32>() -> i128 {
D38::<SCALE_REF>::from_bits(PI_RAW_S37).rescale::<TARGET>().to_bits()
}
pub(crate) fn tau_at_target<const TARGET: u32>() -> i128 {
D38::<SCALE_REF>::from_bits(TAU_RAW_S37).rescale::<TARGET>().to_bits()
}
pub(crate) fn half_pi_at_target<const TARGET: u32>() -> i128 {
D38::<SCALE_REF>::from_bits(HALF_PI_RAW_S37).rescale::<TARGET>().to_bits()
}
pub(crate) fn quarter_pi_at_target<const TARGET: u32>() -> i128 {
D38::<SCALE_REF>::from_bits(QUARTER_PI_RAW_S37).rescale::<TARGET>().to_bits()
}
pub(crate) fn golden_at_target<const TARGET: u32>() -> i128 {
D38::<SCALE_REF>::from_bits(GOLDEN_RAW_S37).rescale::<TARGET>().to_bits()
}
pub(crate) fn e_at_target<const TARGET: u32>() -> i128 {
D38::<SCALE_REF>::from_bits(E_RAW_S37).rescale::<TARGET>().to_bits()
}
crate::macros::consts::decl_decimal_consts!(D38, i128);
impl<const SCALE: u32> D38<SCALE> {
pub const EPSILON: Self = Self(1);
pub const MIN_POSITIVE: Self = Self(1);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core_type::D38s12;
#[test]
fn pi_is_bit_exact_at_scale_12() {
if !crate::rounding::DEFAULT_IS_HALF_TO_EVEN { return; }
assert_eq!(D38s12::pi().to_bits(), 3_141_592_653_590_i128);
}
#[test]
fn tau_is_bit_exact_at_scale_12() {
if !crate::rounding::DEFAULT_IS_HALF_TO_EVEN { return; }
assert_eq!(D38s12::tau().to_bits(), 6_283_185_307_180_i128);
}
#[test]
fn half_pi_is_bit_exact_at_scale_12() {
if !crate::rounding::DEFAULT_IS_HALF_TO_EVEN { return; }
assert_eq!(D38s12::half_pi().to_bits(), 1_570_796_326_795_i128);
}
#[test]
fn quarter_pi_is_bit_exact_at_scale_12() {
if !crate::rounding::DEFAULT_IS_HALF_TO_EVEN { return; }
assert_eq!(D38s12::quarter_pi().to_bits(), 785_398_163_397_i128);
}
#[test]
fn e_is_bit_exact_at_scale_12() {
if !crate::rounding::DEFAULT_IS_HALF_TO_EVEN { return; }
assert_eq!(D38s12::e().to_bits(), 2_718_281_828_459_i128);
}
#[test]
fn golden_is_bit_exact_at_scale_12() {
if !crate::rounding::DEFAULT_IS_HALF_TO_EVEN { return; }
assert_eq!(D38s12::golden().to_bits(), 1_618_033_988_750_i128);
}
#[test]
fn pi_close_to_f64_pi() {
let diff = (D38s12::pi().to_f64() - core::f64::consts::PI).abs();
assert!(diff < 1e-11, "pi diverges from f64 PI by {diff}");
}
#[test]
fn tau_close_to_f64_tau() {
let diff = (D38s12::tau().to_f64() - core::f64::consts::TAU).abs();
assert!(diff < 1e-11, "tau diverges from f64 TAU by {diff}");
}
#[test]
fn half_pi_close_to_f64_frac_pi_2() {
let diff =
(D38s12::half_pi().to_f64() - core::f64::consts::FRAC_PI_2).abs();
assert!(diff < 1e-11, "half_pi diverges from f64 FRAC_PI_2 by {diff}");
}
#[test]
fn quarter_pi_close_to_f64_frac_pi_4() {
let diff =
(D38s12::quarter_pi().to_f64() - core::f64::consts::FRAC_PI_4).abs();
assert!(
diff < 1e-11,
"quarter_pi diverges from f64 FRAC_PI_4 by {diff}"
);
}
#[test]
fn e_close_to_f64_e() {
let diff = (D38s12::e().to_f64() - core::f64::consts::E).abs();
assert!(diff < 1e-11, "e diverges from f64 E by {diff}");
}
#[cfg(feature = "std")]
#[test]
fn golden_close_to_closed_form() {
let expected = (1.0_f64 + 5.0_f64.sqrt()) / 2.0;
let diff = (D38s12::golden().to_f64() - expected).abs();
assert!(diff < 1e-11, "golden diverges from closed-form by {diff}");
}
#[test]
fn epsilon_is_one_ulp() {
assert_eq!(D38s12::EPSILON.to_bits(), 1_i128);
assert!(D38s12::EPSILON > D38s12::ZERO);
}
#[test]
fn min_positive_is_one_ulp() {
assert_eq!(D38s12::MIN_POSITIVE.to_bits(), 1_i128);
assert_eq!(D38s12::MIN_POSITIVE, D38s12::EPSILON);
}
#[test]
fn epsilon_at_scale_6_is_one_ulp() {
type D6 = D38<6>;
assert_eq!(D6::EPSILON.to_bits(), 1_i128);
assert_eq!(D6::MIN_POSITIVE.to_bits(), 1_i128);
}
#[test]
fn pi_at_scale_6_is_bit_exact() {
if !crate::rounding::DEFAULT_IS_HALF_TO_EVEN { return; }
type D6 = D38<6>;
assert_eq!(D6::pi().to_bits(), 3_141_593_i128);
}
#[test]
fn pi_at_scale_0_is_three() {
if !crate::rounding::DEFAULT_IS_HALF_TO_EVEN { return; }
type D0 = D38<0>;
assert_eq!(D0::pi().to_bits(), 3_i128);
}
#[test]
fn pi_at_scale_ref_is_raw_constant() {
type D37 = D38<37>;
assert_eq!(D37::pi().to_bits(), PI_RAW_S37);
}
#[test]
fn pi_at_scale_37_is_raw_constant() {
type D37 = D38<37>;
assert_eq!(D37::pi().to_bits(), PI_RAW_S37);
}
#[test]
fn neg_pi_round_trip() {
if !crate::rounding::DEFAULT_IS_HALF_TO_EVEN { return; }
let pi = D38s12::pi();
let neg_pi = -pi;
assert_eq!(neg_pi.to_bits(), -3_141_592_653_590_i128);
}
}