From 0e556d4e84897d2eeb94c5895c74e0f025afdcc6 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Thu, 29 Oct 2026 00:17:20 +0100 Subject: [PATCH] Count histogram values on a bin edge in that bin Found while testing crates/model/src/chart.rs:1273 (Chart::histogram_bins, bin index computation) Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Opus 5.5 --- crates/model/src/chart.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/model/src/chart.rs b/crates/model/src/chart.rs index 7ad61a50..1b300359 100644 --- a/crates/model/src/chart.rs +++ b/crates/model/src/chart.rs @@ -1270,7 +1270,14 @@ impl Chart { let mut bins: Vec = (0..count).map(|i| Bin { lo: lo + width * i as f64, hi: lo + width * (i + 1) as f64, count: 0 }).collect(); for x in v { // (lo, hi] bins, the first one also holding the minimum. - let i = (((x - lo) / width).ceil() as usize).saturating_sub(1).min(count - 1); + let mut i = (((x - lo) / width).ceil() as usize).saturating_sub(1).min(count - 1); + // The division can round across an edge: settle on the bin whose stored bounds hold x. + while i > 0 && x <= bins[i - 1].hi { + i -= 1; + } + while i + 1 < count && x > bins[i].hi { + i += 1; + } if let Some(b) = bins.get_mut(i) { b.count += 1; } @@ -1535,6 +1542,16 @@ mod chartex_tests { assert_eq!(c.histogram_bins().len(), 7); } + #[test] + fn histogram_value_on_a_bin_edge_counts_in_that_bin() { + let mut c = obs(&[0.0, 2.1, 3.0]); + c.bin_size = Some(0.3); + let bins = c.histogram_bins(); + let own = bins.iter().find(|b| b.lo < 2.1 && 2.1 <= b.hi).expect("a bin holds 2.1"); + assert_eq!(own.count, 1, "2.1 must be counted in ({}, {}]", own.lo, own.hi); + assert_eq!(bins.iter().map(|b| b.count).sum::(), 3); + } + #[test] fn pareto_view_sorts_bins_and_adds_the_cumulative_line() { let mut c = obs(&[1.0, 5.0, 5.0, 5.0, 9.0, 9.0]);