docvortex_core/
exact_mean.rs1pub fn exact_sum_parts(values: &[f64]) -> Option<(i128, i32)> {
5 if values.is_empty() || values.iter().any(|value| !value.is_finite()) {
6 return None;
7 }
8 let mut parts = Vec::with_capacity(values.len());
9 let mut minimum = i32::MAX;
10 for value in values {
11 let bits = value.to_bits();
12 let exponent = ((bits >> 52) & 0x7ff) as i32;
13 let mut mantissa = bits & ((1_u64 << 52) - 1);
14 let mut power = if exponent == 0 {
15 -1074
16 } else {
17 mantissa |= 1_u64 << 52;
18 exponent - 1023 - 52
19 };
20 if mantissa == 0 {
21 continue;
22 }
23 let shift = mantissa.trailing_zeros();
24 mantissa >>= shift;
25 power += shift as i32;
26 minimum = minimum.min(power);
27 let mantissa = if bits >> 63 == 0 {
28 mantissa as i128
29 } else {
30 -(mantissa as i128)
31 };
32 parts.push((mantissa, power));
33 }
34 if parts.is_empty() {
35 return Some((0, 0));
36 }
37 let mut total = 0_i128;
38 for (mantissa, power) in parts {
39 let shift = (power - minimum) as u32;
40 if shift > 126 {
41 return None;
42 }
43 total = total.checked_add(mantissa.checked_mul(1_i128 << shift)?)?;
44 }
45 Some((total, minimum))
46}
47
48#[cfg(test)]
49mod tests {
50 #[test]
52 fn exact_parts_and_fallback() {
53 assert_eq!(super::exact_sum_parts(&[1.0, 2.0, 3.0]), Some((6, 0)));
54 assert_eq!(super::exact_sum_parts(&[1.0, -1.0]), Some((0, 0)));
55 assert_eq!(super::exact_sum_parts(&[-0.0, 0.0]), Some((0, 0)));
56 assert_eq!(
57 super::exact_sum_parts(&[f64::from_bits(1), f64::from_bits(1)]),
58 Some((2, -1074))
59 );
60 assert!(super::exact_sum_parts(&[1e308, 1e308]).is_some());
61 assert!(super::exact_sum_parts(&[1e308, 1e-308]).is_none());
62 assert!(super::exact_sum_parts(&[f64::NAN]).is_none());
63 assert!(super::exact_sum_parts(&[]).is_none());
64 }
65}