mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-24 10:46:50 -06:00
Fix MOD returning wrong sign and magnitude for tiny divisors
Found while testing crates/functions/src/math.rs:305-319 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 5.5
parent
15a705e234
commit
c746eea876
@@ -306,8 +306,8 @@ fn modulo(x: f64, d: f64) -> R<f64> {
|
||||
if d == 0.0 {
|
||||
return Err(CellError::Div0);
|
||||
}
|
||||
let q = (x / d).floor();
|
||||
let r = x - d * q;
|
||||
// `%` is an exact remainder (truncated), so |r| < |d| even for tiny divisors.
|
||||
let r = x % d;
|
||||
// Keep the sign of the divisor and avoid returning |d| from rounding.
|
||||
if r != 0.0 && (r < 0.0) != (d < 0.0) {
|
||||
return Ok(r + d);
|
||||
@@ -1442,6 +1442,19 @@ mod tests {
|
||||
close(ev1("ODD", 0.0), 1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mod_tiny_divisor_stays_in_range() {
|
||||
for (x, d) in [(3.0, 1e-300), (-1.0, 1e-300), (3.0, -1e-300), (-1.0, -1e-300)] {
|
||||
match ev2("MOD", x, d) {
|
||||
Value::Number(r) => {
|
||||
assert!(r == 0.0 || (r < 0.0) == (d < 0.0), "MOD({x}, {d}) = {r}");
|
||||
assert!(r.abs() < d.abs(), "MOD({x}, {d}) = {r}");
|
||||
}
|
||||
other => panic!("MOD({x}, {d}) = {other:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arithmetic() {
|
||||
close(ev2("MOD", 3.0, 2.0), 1.0);
|
||||
|
||||
Reference in New Issue
Block a user