pub fn price_to_earnings(price: f64, eps: f64) -> f64 {
if eps <= 0.0 { f64::INFINITY } else { price / eps }
}
pub fn price_to_book(price: f64, book_value_per_share: f64) -> f64 {
if book_value_per_share <= 0.0 { f64::INFINITY } else { price / book_value_per_share }
}
pub fn earnings_yield(eps: f64, price: f64) -> f64 {
if price <= 0.0 { 0.0 } else { eps / price }
}
pub fn ev_to_ebit(enterprise_value: f64, ebit: f64) -> f64 {
if ebit <= 0.0 { f64::INFINITY } else { enterprise_value / ebit }
}
pub fn dividend_yield(dividend_per_share: f64, price: f64) -> f64 {
if price <= 0.0 { 0.0 } else { dividend_per_share / price }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pe_basic() { assert!((price_to_earnings(100.0, 5.0) - 20.0).abs() < 1e-9); }
#[test]
fn pe_zero_eps_is_inf() { assert!(price_to_earnings(100.0, 0.0).is_infinite()); }
#[test]
fn earnings_yield_reciprocal() {
let pe = price_to_earnings(100.0, 5.0);
let ey = earnings_yield(5.0, 100.0);
assert!((pe * ey - 1.0).abs() < 1e-9);
}
#[test]
fn pb_basic() { assert!((price_to_book(50.0, 25.0) - 2.0).abs() < 1e-9); }
#[test]
fn div_yield_pct() { assert!((dividend_yield(4.0, 100.0) - 0.04).abs() < 1e-9); }
#[test]
fn ev_ebit() { assert!((ev_to_ebit(1_000_000.0, 100_000.0) - 10.0).abs() < 1e-9); }
}