c tier: rationals on int/int division — matches python lumbda

num_div for two integers used to fall back to double when the
quotient wasn't exact. R7RS / python lumbda require exact-in →
exact-out for /. Fixed: the rational_normalize path was already
wired for the is_exact branch; the int/int branch now calls it
too instead of make_double.

(/ 67 7) → 67/7    (was 9.5714285714285712)
(/ 1 3)  → 1/3     (was 0.33333…)
(/ 6 2)  → 3       (exact stays integer)
(+ 1/3 1/6) → 1/2  (rational arithmetic propagates)

C native + C-WASM tier now match python lumbda on / between integers.
asm tier rationals remain pending — that needs bignums in asm first.
native c-test: 205/205 still passes.
This commit is contained in:
russell@unturf.com 2026-06-14 14:23:54 -04:00
parent ef8b9b5819
commit 991ef661e3
No known key found for this signature in database
3 changed files with 9 additions and 7 deletions

View file

@ -419,18 +419,20 @@ Value num_mul(Value a, Value b) {
}
Value num_div(Value a, Value b) {
/* Integer / integer that divides cleanly stays integer (matches Python /
* Scheme semantics for `/` between exacts when the quotient is exact).
* For bignum case we treat as exact division (truncating to integer when
* quotient is exact, else fall back to double for now secp256k1 ops
* never use fractional bignum). */
/* Integer / integer that divides cleanly stays integer; otherwise we
* promote to an exact rational (matches Python lumbda and R7RS:
* `/` between exacts produces an exact result). The previous code
* fell back to double for non-divisible int/int that broke parity
* with the Python tier on (/ 67 7), (/ 1 3), etc. */
if (IS_INTEGER(a) && IS_INTEGER(b)) {
if (big_is_zero(b)) lisp_error("division by zero");
Value q = big_quotient(a, b);
Value r = big_remainder(a, b);
if (big_is_zero(r)) return q;
/* Inexact fallback. */
return make_double(as_number_double(a) / as_number_double(b));
int64_t an, ad, bn, bd;
to_rational(a, &an, &ad);
to_rational(b, &bn, &bd);
return rational_normalize(an * bd, ad * bn);
}
if (is_exact(a) && is_exact(b)) {
int64_t an, ad, bn, bd;