Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions datasketches/src/tdigest/sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1251,15 +1251,24 @@ impl Centroid {
fn add(&mut self, other: Centroid) {
let (self_weight, other_weight) = (self.weight(), other.weight());
let total_weight = self_weight + other_weight;
self.weight = self.weight.saturating_add(other.weight.get());
self.weight = self
.weight
.checked_add(other.weight.get())
.expect("weight overflow");
Comment on lines +1254 to +1257

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of silently saturating_add, panic if overflow.

This should never happen with real inputs, and let it crash should be better than silently holding inaccurate values.

Comment thread
tisonkun marked this conversation as resolved.

let (self_mean, other_mean) = (self.mean, other.mean);
let ratio_self = self_weight / total_weight;
let ratio_other = other_weight / total_weight;
self.mean = self_mean.mul_add(ratio_self, other_mean * ratio_other);
let delta = other_mean - self_mean;
self.mean = if delta.is_finite() {
delta.mul_add(ratio_other, self_mean)
} else {
let ratio_self = self_weight / total_weight;
self_mean.mul_add(ratio_self, other_mean * ratio_other)
};
Comment on lines +1261 to +1267

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If other_mean - self_mean doesn't overflow/underflow, save one mul + one div to reduce precision loss.

This can overflow/underflow, so we fallback to conservative weighted average computed in that case. In both cases, use mul_add to best effort reduce precision loss.

Comment thread
tisonkun marked this conversation as resolved.

debug_assert!(
!self.mean.is_nan(),
"NaN values should never be present in centroids; self: {}, other: {}",
self.mean.is_finite(),
"Centroid's mean must be finite; self: {}, other: {}",
self_mean,
other_mean
);
Expand Down