pub const EPS_F32: f32 = 1.0e-6;
pub const EPS_F64: f64 = 1.0e-12;
#[must_use]
pub fn time_delta_secs(
start: chrono::DateTime<chrono::Utc>,
end: chrono::DateTime<chrono::Utc>,
) -> f64 {
end.signed_duration_since(start)
.to_std()
.map_or(0.0, |d| d.as_secs_f64())
}
#[must_use]
pub fn time_delta_secs_high_res(
start: chrono::DateTime<chrono::Utc>,
end: chrono::DateTime<chrono::Utc>,
) -> f64 {
end.signed_duration_since(start).to_std().map_or(0.0, |d| {
d.as_secs_f64() + f64::from(d.subsec_nanos()) / 1_000_000_000.0
})
}
#[must_use]
pub fn avg_f32(values: &[f32]) -> f32 {
if values.is_empty() {
return 0.0;
}
let sum_f32: f32 = values.iter().copied().sum();
let count_f32: f32 = values.iter().fold(0.0_f32, |acc, _| acc + 1.0);
sum_f32 / count_f32
}
#[must_use]
pub fn haversine_km(lat1: f64, lon1: f64, lat2: f64, lon2: f64) -> f64 {
const EARTH_RADIUS_KM: f64 = 6371.0;
let (lat1, lon1) = (lat1.to_radians(), lon1.to_radians());
let (lat2, lon2) = (lat2.to_radians(), lon2.to_radians());
let dlat = lat2 - lat1;
let dlon = lon2 - lon1;
let sin_dlat = (dlat / 2.0).sin();
let sin_dlon = (dlon / 2.0).sin();
let a = (lat1.cos() * lat2.cos()).mul_add(sin_dlon.powi(2), sin_dlat.powi(2));
let c = 2.0 * a.sqrt().asin();
EARTH_RADIUS_KM * c
}
#[must_use]
pub fn speed_kmh(distance_km: f64, seconds: f64) -> f64 {
if seconds <= 0.0 {
return 0.0;
}
distance_km / (seconds / 3600.0)
}
#[must_use]
pub fn weighted_sum_f64(pairs: &[(f64, f64)]) -> f64 {
let mut acc = 0.0_f64;
for &(value, weight) in pairs {
acc = weight.mul_add(value, acc);
}
acc
}
#[must_use]
pub fn weighted_sum_f32(pairs: &[(f32, f32)]) -> f32 {
let mut acc = 0.0_f32;
for &(value, weight) in pairs {
acc = weight.mul_add(value, acc);
}
acc
}
#[must_use]
pub fn rate_of_change_f64(value_delta: f64, seconds: f64) -> f64 {
if seconds <= 0.0 {
return 0.0;
}
value_delta / seconds
}