feature: fmod floor-mod builtin + document mod signedness#482
Merged
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
98ecd05 to
e03b0c0
Compare
fmod a b returns a non-negative result when b > 0, equivalent to Python a % b. Eliminates the (raw + 7) % 7 workaround every TZ/weekday persona needed with signed mod. Implemented as OP_FMOD (opcode 187), jit_fmod helper, and tree-walker dispatch. mod is unchanged.
Cross-engine regression tests for positive/negative/fractional inputs, zero dividend, zero divisor error, and non-number error. Example file shows weekday and ring-position usage patterns.
SPEC.md: fmod row + mod now notes C-style signed semantics. ai.txt: fmod entry next to mod with floor-mod semantics note. ilo-builtins-math.md: mod gotcha callout, fmod listed. CHANGELOG.md: unreleased entry for fmod.
Result sign matches divisor (Python semantics): fmod 3 -7 = -4, fmod -3 -7 = -3, fmod -10 -7 = -3. Pinned across VM and JIT to prevent silent drift if the sign-correction branch is touched.
Error messages now say "fmod: modulo by zero" across tree/VM/JIT so agents reading stderr can tell which builtin tripped without re-reading the source. Non-number tests now assert "fmod" or "number" appears in the message, and cover both arg positions. NaN/Inf inputs propagate via IEEE 754 f64 % semantics. This matches the existing policy for every other math builtin (abs, sqrt, pow, /) and the "NaN propagates; comparisons false" note in ilo-builtins-math.md. Diverging fmod from that policy would create cross-builtin inconsistency and surprise agents trained on numpy/Python where NaN-propagate is the norm. Pinned with regression tests: fmod NaN 7 -> NaN (propagates) fmod 5 Inf -> 5 (% Inf returns dividend) SPEC.md and ai.txt now call out the NaN/Inf policy on the fmod row.
e03b0c0 to
0f8a545
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
fmod a b: floor-mod that is always non-negative whenb > 0, equivalent to Pythona % bmod's C-style signed-remainder semantics in SPEC.md, ai.txt, and ilo-builtins-math.md(raw + 7) % 7workaround every TZ/weekday persona neededFixes pending.md P1 #9.
Repro before/after
Before:
fmoddid not exist,mod -1 7returns-1, forcing agents to write(raw + 7) % 7.After:
What's in the diff
Builtin::Fmodenum variant,OP_FMODopcode (187), dispatcher in tree-walker interpreter, VM, JIT (jit_fmod helper), and AOT (cranelift compile path)examples/fmod.ilowith weekday and ring-position demosfmod 3 -7 = -4,fmod -3 -7 = -3,fmod -10 -7 = -3cross-engineNotes
Builtin::ALLinsertion at position 9: InsertingFmodbetweenModandClampreorders the on-wire tag for every later variant. Pre-1.0 this is acceptable (no persisted bytecode contract yet), but flagging for the changelog when 1.0 ships.skills/ilo/ilo-builtins-math.mdwhich is updated in this PR.Test plan
fmod -1 7= 6 on --vm, --jit, AOTfmod -7 7= 0 on --vm, --jitfmod 1.5 1= 0.5 on --vm, --jitfmod -1.5 1= 0.5 on --vm, --jitfmod -3 -7= -3 on --vm, --jit (negative divisor)fmod 3 -7= -4 on --vm, --jit (negative divisor)fmod -10 -7= -3 on --vm, --jit (negative divisor)fmod 5 0errors on --vm, --jitfmod "a" 7errors on --vm, --jitmod -1 7still returns -1 (no regression)cargo fmt -- --checkcleanFollow-ups
modstays as-is (breaking change would be 26.X)