use super::NumericValue;
use std::f64::consts::{PI, E, TAU, SQRT_2, LN_2, LN_10, FRAC_1_PI, FRAC_2_PI, FRAC_PI_2, FRAC_PI_3, FRAC_PI_4, FRAC_PI_6, FRAC_PI_8};
pub struct MathConstants;
impl MathConstants {
pub const PI: f64 = PI;
pub const TAU: f64 = TAU;
pub const E: f64 = E;
pub const GOLDEN_RATIO: f64 = 1.618033988749895;
pub const EULER_GAMMA: f64 = 0.5772156649015329;
pub const SQRT_2: f64 = SQRT_2;
pub const SQRT_3: f64 = 1.7320508075688772;
pub const SQRT_5: f64 = 2.23606797749979;
pub const SQRT_PI: f64 = 1.7724538509055159;
pub const SQRT_2PI: f64 = 2.5066282746310005;
pub const FRAC_1_SQRT_2: f64 = std::f64::consts::FRAC_1_SQRT_2;
pub const FRAC_1_SQRT_2PI: f64 = 0.3989422804014327;
pub const LN_2: f64 = LN_2;
pub const LN_3: f64 = 1.0986122886681097;
pub const LN_10: f64 = LN_10;
pub const LN_PI: f64 = 1.1447298858494002;
pub const LOG2_E: f64 = std::f64::consts::LOG2_E;
pub const LOG10_E: f64 = std::f64::consts::LOG10_E;
pub const LOG2_10: f64 = 3.3219280948873626;
pub const LOG10_2: f64 = std::f64::consts::LOG10_2;
pub const FRAC_1_PI: f64 = FRAC_1_PI;
pub const FRAC_2_PI: f64 = FRAC_2_PI;
pub const FRAC_PI_2: f64 = FRAC_PI_2;
pub const FRAC_PI_3: f64 = FRAC_PI_3;
pub const FRAC_PI_4: f64 = FRAC_PI_4;
pub const FRAC_PI_6: f64 = FRAC_PI_6;
pub const FRAC_PI_8: f64 = FRAC_PI_8;
pub const FRAC_3PI_2: f64 = 4.71238898038469;
pub const FRAC_2PI_3: f64 = 2.0943951023931955;
pub const FRAC_3PI_4: f64 = 2.356194490192345;
pub const FRAC_5PI_6: f64 = 2.6179938779914944;
pub const CATALAN: f64 = 0.915965594177219;
pub const APERY: f64 = 1.2020569031595943;
pub const KHINCHIN: f64 = 2.6854520010653064;
pub const GLAISHER_KINKELIN: f64 = 1.2824271291006226;
pub const DEG_TO_RAD: f64 = 0.017453292519943295;
pub const RAD_TO_DEG: f64 = 57.29577951308232;
}
pub struct PhysicalConstants;
impl PhysicalConstants {
pub const SPEED_OF_LIGHT: f64 = 299792458.0;
pub const PLANCK: f64 = 6.62607015e-34;
pub const PLANCK_REDUCED: f64 = 1.0545718176461565e-34;
pub const ELEMENTARY_CHARGE: f64 = 1.602176634e-19;
pub const ELECTRON_MASS: f64 = 9.1093837015e-31;
pub const PROTON_MASS: f64 = 1.67262192369e-27;
pub const NEUTRON_MASS: f64 = 1.67492749804e-27;
pub const ATOMIC_MASS_UNIT: f64 = 1.66053906660e-27;
pub const AVOGADRO: f64 = 6.02214076e23;
pub const BOLTZMANN: f64 = 1.380649e-23;
pub const GAS_CONSTANT: f64 = 8.314462618;
pub const STEFAN_BOLTZMANN: f64 = 5.670374419e-8;
pub const WIEN_DISPLACEMENT: f64 = 2.897771955e-3;
pub const GRAVITATIONAL: f64 = 6.67430e-11;
pub const STANDARD_GRAVITY: f64 = 9.80665;
pub const STANDARD_ATMOSPHERE: f64 = 101325.0;
pub const VACUUM_PERMEABILITY: f64 = 1.25663706212e-6;
pub const VACUUM_PERMITTIVITY: f64 = 8.8541878128e-12;
pub const IMPEDANCE_OF_VACUUM: f64 = 376.730313668;
pub const FINE_STRUCTURE: f64 = 7.2973525693e-3;
pub const BOHR_RADIUS: f64 = 5.29177210903e-11;
pub const ELECTRON_RADIUS: f64 = 2.8179403262e-15;
pub const THOMSON_CROSS_SECTION: f64 = 6.6524587321e-29;
pub const BOHR_MAGNETON: f64 = 9.2740100783e-24;
pub const NUCLEAR_MAGNETON: f64 = 5.0507837461e-27;
pub const ABSOLUTE_ZERO_CELSIUS: f64 = -273.15;
pub const ICE_POINT: f64 = 273.15;
pub const STANDARD_TEMPERATURE: f64 = 273.15;
pub const STANDARD_PRESSURE: f64 = 100000.0;
}
pub struct UnitConversions;
impl UnitConversions {
pub fn degrees_to_radians(degrees: f64) -> f64 {
degrees * MathConstants::DEG_TO_RAD
}
pub fn radians_to_degrees(radians: f64) -> f64 {
radians * MathConstants::RAD_TO_DEG
}
pub fn celsius_to_kelvin(celsius: f64) -> f64 {
celsius + PhysicalConstants::ICE_POINT
}
pub fn kelvin_to_celsius(kelvin: f64) -> f64 {
kelvin - PhysicalConstants::ICE_POINT
}
pub fn fahrenheit_to_celsius(fahrenheit: f64) -> f64 {
(fahrenheit - 32.0) * 5.0 / 9.0
}
pub fn celsius_to_fahrenheit(celsius: f64) -> f64 {
celsius * 9.0 / 5.0 + 32.0
}
pub fn joules_to_ev(joules: f64) -> f64 {
joules / PhysicalConstants::ELEMENTARY_CHARGE
}
pub fn ev_to_joules(ev: f64) -> f64 {
ev * PhysicalConstants::ELEMENTARY_CHARGE
}
}
pub fn get_constant(name: &str) -> Option<NumericValue> {
match name {
"pi" | "π" => Some(NumericValue::real(MathConstants::PI)),
"tau" | "τ" => Some(NumericValue::real(MathConstants::TAU)),
"e" => Some(NumericValue::real(MathConstants::E)),
"golden-ratio" | "φ" => Some(NumericValue::real(MathConstants::GOLDEN_RATIO)),
"euler-gamma" | "γ" => Some(NumericValue::real(MathConstants::EULER_GAMMA)),
"sqrt-2" => Some(NumericValue::real(MathConstants::SQRT_2)),
"sqrt-3" => Some(NumericValue::real(MathConstants::SQRT_3)),
"sqrt-5" => Some(NumericValue::real(MathConstants::SQRT_5)),
"sqrt-pi" => Some(NumericValue::real(MathConstants::SQRT_PI)),
"ln-2" => Some(NumericValue::real(MathConstants::LN_2)),
"ln-10" => Some(NumericValue::real(MathConstants::LN_10)),
"catalan" => Some(NumericValue::real(MathConstants::CATALAN)),
"apery" => Some(NumericValue::real(MathConstants::APERY)),
"speed-of-light" | "c" => Some(NumericValue::real(PhysicalConstants::SPEED_OF_LIGHT)),
"planck" | "h" => Some(NumericValue::real(PhysicalConstants::PLANCK)),
"planck-reduced" | "ℏ" => Some(NumericValue::real(PhysicalConstants::PLANCK_REDUCED)),
"elementary-charge" | "q" => Some(NumericValue::real(PhysicalConstants::ELEMENTARY_CHARGE)),
"electron-mass" | "me" => Some(NumericValue::real(PhysicalConstants::ELECTRON_MASS)),
"proton-mass" | "mp" => Some(NumericValue::real(PhysicalConstants::PROTON_MASS)),
"avogadro" | "NA" => Some(NumericValue::real(PhysicalConstants::AVOGADRO)),
"boltzmann" | "k" => Some(NumericValue::real(PhysicalConstants::BOLTZMANN)),
"gas-constant" | "R" => Some(NumericValue::real(PhysicalConstants::GAS_CONSTANT)),
"gravitational" | "G" => Some(NumericValue::real(PhysicalConstants::GRAVITATIONAL)),
"fine-structure" | "α" => Some(NumericValue::real(PhysicalConstants::FINE_STRUCTURE)),
_ => None,
}
}
pub fn list_constants() -> Vec<&'static str> {
vec![
"pi", "τ", "e", "golden-ratio", "euler-gamma",
"sqrt-2", "sqrt-3", "sqrt-5", "sqrt-pi",
"ln-2", "ln-10", "catalan", "apery",
"speed-of-light", "planck", "planck-reduced",
"elementary-charge", "electron-mass", "proton-mass",
"avogadro", "boltzmann", "gas-constant",
"gravitational", "fine-structure",
]
}
#[cfg(test)]
mod tests {
use super::*;
use std::f64::EPSILON;
#[test]
fn test_mathematical_constants() {
assert!((MathConstants::PI - std::f64::consts::PI).abs() < EPSILON);
assert!((MathConstants::E - std::f64::consts::E).abs() < EPSILON);
assert!((MathConstants::GOLDEN_RATIO - 1.618033988749895).abs() < EPSILON);
assert!((MathConstants::TAU - 2.0 * MathConstants::PI).abs() < EPSILON);
assert!((MathConstants::FRAC_1_SQRT_2 - 1.0 / MathConstants::SQRT_2).abs() < 1e-15);
}
#[test]
fn test_physical_constants() {
assert!(PhysicalConstants::SPEED_OF_LIGHT > 2.9e8);
assert!(PhysicalConstants::PLANCK > 6e-34 && PhysicalConstants::PLANCK < 7e-34);
assert!(PhysicalConstants::AVOGADRO > 6e23 && PhysicalConstants::AVOGADRO < 7e23);
}
#[test]
fn test_unit_conversions() {
let right_angle_rad = UnitConversions::degrees_to_radians(90.0);
assert!((right_angle_rad - MathConstants::FRAC_PI_2).abs() < 1e-10);
let right_angle_deg = UnitConversions::radians_to_degrees(MathConstants::FRAC_PI_2);
assert!((right_angle_deg - 90.0).abs() < 1e-10);
let boiling_k = UnitConversions::celsius_to_kelvin(100.0);
assert!((boiling_k - 373.15).abs() < EPSILON);
let freezing_c = UnitConversions::kelvin_to_celsius(273.15);
assert!((freezing_c - 0.0).abs() < EPSILON);
let body_temp_f = UnitConversions::celsius_to_fahrenheit(37.0);
assert!((body_temp_f - 98.6).abs() < 0.1);
}
#[test]
fn test_constant_lookup() {
let pi_val = get_constant("pi").unwrap();
assert!((pi_val.to_f64().unwrap() - MathConstants::PI).abs() < EPSILON);
let c_val = get_constant("speed-of-light").unwrap();
assert!((c_val.to_f64().unwrap() - PhysicalConstants::SPEED_OF_LIGHT).abs() < EPSILON);
assert!(get_constant("nonexistent").is_none());
}
#[test]
fn test_constant_precision() {
let pi_str = format!("{:.50}", MathConstants::PI);
assert!(pi_str.starts_with("3.14159265358979323846264338327950288419716939937510"));
let e_str = format!("{:.50}", MathConstants::E);
assert!(e_str.starts_with("2.71828182845904523536028747135266249775724709369995"));
}
}