Repository navigation
Lua: a real modulo is Blizzard.j's ModuloReal formula, as on Jass - #1433
Conversation
Measured on the 3.0.0 client, Lua's float % differs from fmod with the ModuloReal correction for a negative dividend, and the fmod form is the one which agrees with Jass (-0.1 % 7: 6.900000064 against 6.899999616). The integer % by a positive literal agrees with Jass and stays.
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. More of your lovely PRs please. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Measured on the 3.0.0 client, neither math.fmod nor Lua's float % gives Jass's real modulo in the game (360 % 7: 3.0000153), while a - R2I(a / b) * b, plus b when negative, computed in the game's Lua matches Jass on every probed operand both read alike.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4a3ed1621d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
WurstOperator.moduloReal, which the interpreter and its ModuloReal mock use, was the exact remainder, while Jass and now Lua compute a - R2I(a / b) * b in float. It is that formula now, with the interpreter's measured R2I shared as WurstOperator.realToInt.
|
@codex review |
|
Codex Review: Didn't find any major issues. Can't wait for the next one! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0f4f268474
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A real modulo on Jass is Blizzard.j's
ModuloReal:a - I2R(R2I(a / b)) * b, plusbwhen that is negative. On Lua it wasmath.fmodwith that correction, and since #1426 Lua's float%for a divisor of at least 1. The three agree in the test Lua, which computes in double. Measured on the 3.0.0 client, they do not agree in the game. Only the Blizzard formula, computed in the game's Lua, gives Jass's results, so a real modulo on Lua is now that formula.Measured
One probe, built as Jass and as Lua (dividends come from a function call, so nothing is folded), run in game:
%(master)360. % 7.7.5 % 360.-7.5 % 2.5(divisor at run time)16777216. % 3.-0.1 % 7.With this PR, all 54 probe lines whose operands Jass and Lua read alike are identical to Jass. This covers 27 dividends, five literal divisors, run-time divisors of 2.5, 1 and 0.3, and the integer lines. The remaining 14 lines are dividends which the two read differently in the first place: Jass reads the literals
0.1,3.14159and123456.789one float off, and1e10wraps. No modulo rule changes that.The integer
modby a positive literal (Lua's%, from #1426) agreed with Jass'sModuloIntegeron every integer probed, including the 32-bit edges, and stays as it is.What changes
__wurst_modRealis Blizzard.j's formula:q = a / b; r = a - R2I(q) * b; if r < 0 then r = r + b.R2Iis the intrinsic whichR2Icalls already lower to; with the quotient in a local it is printed in place as Lua arithmetic, so an inlined real modulo has no call when the quotient is in range. The integer quotient converts to a real in the multiplication, asI2Rdoes.__wurst_rawR2Iintrinsic.WurstOperator.moduloReal, which the interpreter and itsModuloRealmock use, was the exact remainder (Java's%). It is now the same formula in float, withR2Ias the interpreter's measuredR2I(truncating, wrapping to 32 bits; nowWurstOperator.realToInt, shared with that mock). Compile-time code and unit tests compute a real modulo the way the game does. For a quotient past 2^24 the two differ by more than rounding:1e9 % 3is -29 by the formula and 1 as the exact remainder. Constant folding never folds a real modulo, so it is unaffected.WurstOperator.divideReal, used by both). Measured on the 3.0.0 client, Jass stops the thread on1. / 0.,-1. / 0.,0. / 0.,5. % 0.andModuloReal(5., 0.). Before, the interpreters answered an infinity, and the formula then answered the dividend. The game's Lua does not stop:1. / 0.is 1.7014e38,0. / 0.is 1. The Lua backend adds no check here, because one would cost every real division with a divisor that is not a literal.%intrinsic and the real fmod intrinsic (rawFloorModReal,rawFmodReal), with their translator fields, translations and interpreter mocks.docs/WC3_RUNTIME.md("Numbers") records the measurement. AGENTS.md §7 says a real modulo on Lua is Blizzard.j's formula, nevermath.fmodor the float%.Tests
modByADivisorThatBecomesALiteralIsTheLuaOperator,modKeepsTheSignOfANegativeZeroOnLuaand the helper-lowering test now expect the formula, printed in place. They expect no%,math.fmodor__wurst_rawR2I(call for a real modulo, and still%for the integer cases. Each failed on master.-0.0keeps its sign under the formula, as before.realModIsModuloRealsFormulaInEveryRun(new):x % yequals the formula written out in Wurst, compared exactly (!=, since Jass's==on reals has a tolerance), in the interpreter, on Jass and on Lua, including1e9 % 3. It fails on master in the interpreter run.realDivisionByZeroStopsTheInterpreters(new):1. / 0.,5. % 0.and0. / 0.stop the interpreter and the Jass interpreter. It fails on master, which goes on with an infinity.