Skip to content

Commit ee06b2b

Browse files
committed
Fix translating MOD to R
`x MOD y` should be `x - y * trunc(x / y)`.
1 parent 00a4125 commit ee06b2b

2 files changed

Lines changed: 15 additions & 2 deletions

File tree

crates/data-dict/src/emit/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,16 @@ mod r_tests {
476476
fn modulo_takes_its_sign_from_the_dividend() {
477477
// R's `%%` follows the divisor, so the language's rule is arithmetic.
478478
assert_eq!(r("MOD(n, 3) = 0"), "n - 3L * trunc(n / 3L) == 0L");
479+
// A compound dividend keeps its brackets inside the division, or `/`
480+
// would take only the last term.
481+
assert_eq!(
482+
r("MOD(n + 1, 3) = 0"),
483+
"n + 1L - 3L * trunc((n + 1L) / 3L) == 0L"
484+
);
485+
assert_eq!(
486+
r("MOD(n, qty + 1) = 0"),
487+
"n - (qty + 1L) * trunc(n / (qty + 1L)) == 0L"
488+
);
479489
}
480490

481491
#[test]

crates/data-dict/src/emit/r_tidyverse.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,10 +398,13 @@ fn write_func(cx: &mut Ctx, op: Op, args: &[TypedExpr]) -> Result<(), Unsupporte
398398
cx.child(p::ADD, Side::Left, x)?;
399399
cx.push(" - ");
400400
cx.child(p::MUL, Side::Right, y)?;
401+
// The division inside `trunc` is an operator position, not a
402+
// delimited one: a compound dividend has to keep its brackets or
403+
// `/` steals its last term.
401404
cx.push(" * trunc(");
402-
cx.free(x)?;
405+
cx.child(p::MUL, Side::Left, x)?;
403406
cx.push(" / ");
404-
cx.free(y)?;
407+
cx.child(p::MUL, Side::Right, y)?;
405408
cx.push(")");
406409
}
407410
Op::Min | Op::Max | Op::Sum | Op::Avg => {

0 commit comments

Comments
 (0)