/* cargo new irr inside projects cd irr cd src copy in main.rs cargo make cargo run better than recursive because: Uses a standard root-finding algorithm (bisection) that is more robust Nicer handling of edge cases (e.g., negative interest rates or no root) Clear separation of npv and irr logic */ fn main() { let investment = 25000.0; let cash_flows = vec![3500.0, 100.0, 4000.0, 100.0, -300.0, 4000.0, 2300.0, -150.0, 5600.0,321.0, -100.0, 24900.0]; let tol = investment / 10000.0; match irr(&cash_flows, investment, tol) { Some(rate) => println!("IRR = {:.3}%", rate), None => println!("No solution found"), } } fn npv(cash_flows: &[f64], rate: f64) -> f64 { cash_flows.iter() .enumerate() .map(|(i, &cf)| cf / (1.0 + rate).powi((i + 1) as i32)) .sum() } fn irr(cash_flows: &[f64], investment: f64, tol: f64) -> Option { let mut low = -0.99; // can't be -1.0 or division by zero let mut high = 2.0; // upper guess: 200% let mut mid; for _ in 0..1000 { mid = (low + high) / 2.0; let npv_mid = npv(cash_flows, mid); let diff = investment - npv_mid; if diff.abs() < tol { return Some(mid * 100.0); // convert to percent } let npv_low = npv(cash_flows, low); if (investment - npv_low) * diff < 0.0 { high = mid; } else { low = mid; } } None // did not converge }