fn calculate_churn_statistics_scalar(files: &[FileChurnMetrics]) -> (f64, f64, f64) {
if files.is_empty() {
return (0.0, 0.0, 0.0);
}
let scores: Vec<f64> = files.iter().map(|f| f64::from(f.churn_score)).collect();
let n = scores.len() as f64;
let sum: f64 = scores.iter().sum();
let mean = sum / n;
let variance = scores.iter().map(|&s| (s - mean).powi(2)).sum::<f64>() / n;
let stddev = variance.sqrt();
(mean, variance, stddev)
}
#[cfg(feature = "simd")]
fn calculate_churn_statistics_simd(files: &[FileChurnMetrics]) -> (f64, f64, f64) {
use trueno::Vector;
if files.is_empty() {
return (0.0, 0.0, 0.0);
}
let scores_f32: Vec<f32> = files.iter().map(|f| f.churn_score).collect();
let vec = Vector::from_slice(&scores_f32);
let mean = match vec.mean() {
Ok(m) => f64::from(m),
Err(_) => return calculate_churn_statistics_scalar(files),
};
let variance = match vec.variance() {
Ok(v) => f64::from(v),
Err(_) => return calculate_churn_statistics_scalar(files),
};
let stddev = variance.sqrt();
(mean, variance, stddev)
}
#[cfg(feature = "simd")]
fn calculate_churn_statistics(files: &[FileChurnMetrics]) -> (f64, f64, f64) {
calculate_churn_statistics_simd(files)
}
#[cfg(not(feature = "simd"))]
fn calculate_churn_statistics(files: &[FileChurnMetrics]) -> (f64, f64, f64) {
calculate_churn_statistics_scalar(files)
}