Hi all,

I got into a discussion with some Actuaries on different implementations to a simple Actuarial modeling problem. We all implemented a simple 10-period net present value. Here is my simple implementation:

```
pub fn npv(mortality_rates: &Vec<f64>, lapse_rates: &Vec<f64>, interest_rate: f64, sum_assured: f64, premium: f64, init_pols: f64, term: Option<usize>) -> f64 {
let term = term.unwrap_or_else(|| mortality_rates.len());
let mut result = 0.0;
let mut inforce = init_pols;
let v: f64 = 1.0 / (1.0 + interest_rate);
for (t, (q, w)) in mortality_rates.iter().zip(lapse_rates).enumerate() {
let no_deaths = if t < term {inforce * q} else {0.0};
let no_lapses = if t < term {inforce * w} else {0.0};
let premiums = inforce * premium;
let claims = no_deaths * sum_assured;
let net_cashflow = premiums - claims;
result += net_cashflow * v.powi(t as i32);
inforce = inforce - no_deaths - no_lapses;
}
result
}
```

I bench marked it and it ran in **364.35 ns**.

Another person re-implemented my version in Julia:

```
function npv3(q,w,P,S,r,term=nothing)
term = isnothing(term) ? length(q) + 1 : term + 1
inforce = 1.0
result = 0.0
for (t,(q,w)) in enumerate(zip(q,w))
deaths = t < term ? inforce * q : 0.0
lapses = t < term ? inforce * w : 0.0
premiums = inforce * P
claims = deaths * S
ncf = premiums - claims
result += ncf * (1 / ( 1 + r)) ^ (t-1)
inforce = inforce - deaths - lapses
end
return result
end
```

This user bench marked his version and found that it ran in **135 ns**. This is not really the problem to decide between Rust vs Julia but it is interesting. He is using an M1 Mac where Julia runs on Rosetta (I'm on windows 10) so it's hard to compare these two implementations in a meaningful way.

My question is, is there anything obvious that I am missing with the Rust implemenation that could improve it? If anyone has an M1 Mac and could bench mark on their machine that would be really interesting.