Skip to content

Commit e482632

Browse files
committed
Fix bug that point-point error may cause compute_key_point_f64 loop forever
1 parent 54da6c8 commit e482632

File tree

1 file changed

+23
-7
lines changed

1 file changed

+23
-7
lines changed

plotters/src/coord/ranged1d/types/numeric.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ macro_rules! gen_key_points_comp {
119119

120120
let mut scale = (10f64).powf((range.1 - range.0).log(10.0).floor());
121121
// The value granularity controls how we round the values.
122+
// To avoid generating key points like 1.00000000001, we round to the nearest multiple of the
123+
// value granularity.
124+
// By default, we make the granularity as the 1/10 of the scale.
122125
let mut value_granularity = scale / 10.0;
123126
fn rem_euclid(a: f64, b: f64) -> f64 {
124127
if b > 0.0 {
@@ -154,15 +157,21 @@ macro_rules! gen_key_points_comp {
154157
}
155158

156159
let mut ret = vec![];
157-
let mut left = range.0 + scale - rem_euclid(range.0, scale);
160+
// In some extreme cases, left might be too big, so that (left + scale) - left == 0 due to
161+
// floating point error.
162+
// In this case, we may loop forever. To avoid this, we need to use two variables to store
163+
// the current left value. So we need keep a left_base and a left_relative.
164+
let left = range.0 + scale - rem_euclid(range.0, scale);
165+
let left_base = (left / value_granularity).floor() * value_granularity;
166+
let mut left_relative = left - left_base;
158167
let right = range.1 - rem_euclid(range.1, scale);
159-
while left <= right {
160-
let new_left = (left / value_granularity).round() * value_granularity;
161-
if new_left < range.0 {
162-
left = new_left + value_granularity;
168+
while left_relative <= right - left_base {
169+
let new_left_relative = (left_relative / value_granularity).round() * value_granularity;
170+
if new_left_relative < 0.0 {
171+
left_relative += value_granularity;
163172
}
164-
ret.push(left as $type);
165-
left += scale;
173+
ret.push((left_relative + left_base) as $type);
174+
left_relative += scale;
166175
}
167176
return ret;
168177
}
@@ -388,4 +397,11 @@ mod test {
388397
let points = coord.key_points(500);
389398
assert!(points.len() <= 500);
390399
}
400+
401+
#[test]
402+
fn regression_test_issue_358_key_points_no_hang_2() {
403+
let coord: RangedCoordf64 = (10000000000001f64..10000000000002f64).into();
404+
let points = coord.key_points(500);
405+
assert!(points.len() <= 500);
406+
}
391407
}

0 commit comments

Comments
 (0)