Skip to content

Commit 7bd2e5a

Browse files
baku-ccronclaude
andcommitted
Merge origin/main (#352, #428, #432) into fuzz-full-domain-425
diffLimit takes the root, as #428's pow bound does, and keeps this branch's floor term in the same helper. The scan log is the union of both sides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 parents b15b531 + 8b6a8ed commit 7bd2e5a

19 files changed

Lines changed: 2648 additions & 386 deletions

‎README.md‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ rounding tie can round to either neighbour:
169169
- `pow10`: half a unit in the 41st digit plus 3.28e-8 of a unit, under
170170
5.0000004e-41 relative.
171171
- `log10`: half a unit in the 41st digit plus 2e-50 absolute.
172-
- `pow`: 5.0000004e-41 + 3N·1e-75 relative, for N the integer part of |b|.
172+
- `pow`: 5.0000004e-41 + N·min(K1, K2·d) relative, for N the integer part of |b|
173+
and d = max(|a|, 1/|a|) - 1, with K1 = 1.7273e-76 and K2 = 1.5e-38 for b > 0,
174+
and K1 = 1.1728e-75 and K2 = 3.4786e-38 for b < 0.
173175
- `sqrt`: correctly rounded, half a unit in the 41st digit, under 5e-41
174176
relative.
175177

@@ -182,8 +184,9 @@ carry above the largest Float is truncated to int224 instead.
182184
monotone. For a < b the order of the results can flip by exactly one unit in the
183185
last place, only when both true values lie within the larger raw error of the
184186
same rounding tie, and never by more. The raw error, before rounding, is 3.28e-8
185-
of a unit for `pow10`, 2e-50 for `log10`, and 3.33e-48 + 3N·1e-75 relative for
186-
`pow`. Callers must not rely on strict ordering at one-ulp resolution.
187+
of a unit for `pow10`, 2e-50 for `log10`, and 3.33e-48 + N·min(K1, K2·d)
188+
relative for `pow`, with N, d, K1 and K2 as above. Callers must not rely on
189+
strict ordering at one-ulp resolution.
187190

188191
Exact results stay exact: powers of ten (`pow10(k)` is `10^k`, `log10(10^k)` is
189192
`k`), and integer and fractional powers, roots included, with at most 41
@@ -290,10 +293,10 @@ and an exactly representable power such as `10^2` is exact.
290293

291294
`pow` calculates an integer exponent by squaring, and the fractional component
292295
of a non-integer exponent as `pow10(frac(b) * log10(a))` with its guard digits,
293-
then rounds the product to 41 significant digits, so it is within about 5e-41
294-
relative of the true value and a power such as `4^1.5` is exact. A fractional
295-
part of exactly a half instead takes the square root of `a^(2N+1)`, for N the
296-
integer part of |b|.
296+
then rounds the product to 41 significant digits, so it is within the bound
297+
above of the true value and a power such as `4^1.5` is exact. A fractional part
298+
of exactly a half instead takes the square root of `a^(2N+1)`, for N the integer
299+
part of |b|.
297300

298301
`sqrt` takes the integer square root of the coefficient scaled to 81 or 82
299302
digits and rounds it to nearest, so it is correctly rounded and a root such as

‎audit/mutation-test-scans.json‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,28 @@
343343
"filed": []
344344
}
345345
},
346+
{
347+
"timestamp": "2026-10-07T21:26:43Z",
348+
"commit": "2889ea87444d6b960a3dc086a47313f5183c0530",
349+
"testsAfterCommit": "90655a15019f154e388d2a7986c8f1bf98724b1e",
350+
"publishedTag": "sol-v0.2.22",
351+
"commitsAheadOfTag": 1,
352+
"scope": "issue #306 inline-series change: LibDecimalFloatImplementation.log10Ratio (7 fixed atanh terms, mulDivFixed written out for the first three, native multiplies after) and exp10Fixed (26 mulDivFixed calls written out). 86 mutants. Probe suite: forge test --mc 'Log10|Pow|Sqrt|Exp10|Precision|Transcend', plus SeriesMain for the after numbers; test counts are that suite. All 86 were probed against the pre-existing suite at commit (79 killed); the 7 survivors were re-probed with the new tests. Equivalent: E56 (step 1 multiplies 1e50 or 10^0.5 1e50, and neither product borrows), E52 (exhaustive modular search over all 65536 step results and every series value finds no carry in the final multiply), E115 (the series at x = 2^-16 floors to exactly the last step's constant, checked for all 32768 prefixes). Survived: R41 (the z^2 carry needs z^2 mod 2^256 within floor(z^2 / 2^256) < 2^55 of 2^256 for z < 5.1e46; heuristically about 3e-15 such z exist in the domain, but this was not exhaustively proven and no input was constructed).",
353+
"tool": "adversarial-mutation-test",
354+
"skillVersion": "0.35.0",
355+
"summary": {
356+
"behaviours": 86,
357+
"killedBefore": 79,
358+
"killedAfter": 3,
359+
"equivalent": 3,
360+
"survived": 1,
361+
"candidates": 0,
362+
"confirmed": 0,
363+
"testsBefore": 136,
364+
"testsAfter": 146,
365+
"filed": []
366+
}
367+
},
346368
{
347369
"timestamp": "2026-10-07T22:03:31Z",
348370
"commit": "a5561f85600ab9aaeaf7b077c862c5a8a5a417f7",
@@ -490,6 +512,28 @@
490512
"filed": []
491513
}
492514
},
515+
{
516+
"timestamp": "2026-10-07T23:40:00Z",
517+
"commit": "69c8afb9a5f7ecbe8f2e624cfd0d2a0853913a9d",
518+
"testsAfterCommit": "d22ea5d10bda8aae53706b23cb88a57ed62e4caa",
519+
"publishedTag": "sol-v0.2.23",
520+
"commitsAheadOfTag": 5,
521+
"scope": "issue #306 follow-up: the z^2 step of LibDecimalFloatImplementation.log10Ratio, now u^2 + floor((2 u v 1e25 + v^2) / 1e50) for z = u 1e25 + v, replacing the 512-bit multiply whose carry was the R41 survivor of the previous entry (R40 and R41 no longer exist). 7 mutants. Probe suite: forge test --mc 'Log10|Pow|Sqrt|Exp10|Precision|Transcend|SeriesMain' at commit, all 7 killed by pre-existing tests; testsAfter is the SeriesMainEquivalence suite alone, which also kills all 7. A +1 on v^2 was not probed: it changes the floor only when z^2 = -1 mod 1e50, impossible as -1 is not a square mod 4.",
522+
"tool": "adversarial-mutation-test",
523+
"skillVersion": "0.35.0",
524+
"summary": {
525+
"behaviours": 7,
526+
"killedBefore": 7,
527+
"killedAfter": 7,
528+
"equivalent": 0,
529+
"survived": 0,
530+
"candidates": 0,
531+
"confirmed": 0,
532+
"testsBefore": 145,
533+
"testsAfter": 10,
534+
"filed": []
535+
}
536+
},
493537
{
494538
"timestamp": "2026-10-07T23:55:24Z",
495539
"commit": "0312b68d23e8d229dd18f5d95522b4f67ce135fa",
@@ -959,6 +1003,27 @@
9591003
"filed": []
9601004
}
9611005
},
1006+
{
1007+
"timestamp": "2026-10-11T12:24:30Z",
1008+
"commit": "4ecd21232b7a94ce357032e4dbc8956f738e5975",
1009+
"testsAfterCommit": "a9f6f9372d063112a032f30bd21c860b50fd6d05",
1010+
"publishedTag": "sol-v0.2.38",
1011+
"commitsAheadOfTag": 20,
1012+
"scope": "Issue #424: pow large |b| near a = 1, the integer leg (squaring, result multiply, inverse) and the past-int256 b guard. Before = forge test --mc \"LibDecimalFloatPowTest|LibDecimalFloatPrecisionTest\" at main 4ecd212 (bound 5.0000004e-41 + 3N 1e-75, |b| <= 1e6 in powInputs). After = the same suites at a9f6f93: bound 5.0000004e-41 + N min(K1, K2 d), powInputs near one with |b| past 1e75, testPowNearOneLargeExponent against Rust truth_pow, and testPowIntegerLegAtRoundingTie. Mutants of src/lib/LibDecimalFloat.sol: M1 squaring drops one more unit of an inexact full-width square, M2 result multiply drops one more unit of an inexact product, M3 inverse drops one more unit when its last digit is nonzero, M3b inverse drops one more unit when a times it is not one, M4 squaring keeps only 70 digits, M5 past-int256 b reverts on the wrong side, M6 integer b scales one decade short. Before: M5, M6 killed; M1-M4, M3b survive. After: all killed. M2 survived the bound tests, as it moves the result under 256 units of 1e-75, and is killed by testPowIntegerLegAtRoundingTie: inputs where each step by its own rule (squared partial the floor of the exact square, result multiply truncated toward zero) leaves the unrounded power exactly on a 41 digit tie, (1 + 5e-66)^3e25, (1 - 5e-67)^3e25, (1 - 5e-67)^-3e26 and (5e13 + 5)^3, so one unit more dropped rounds to the other neighbour. Two other result-multiply forms were already killed by the suite before that test: one more unit dropped whenever the multiply sheds digits (testPows) and whenever its last digit is nonzero (testPowFloor, testPowFractionExact, testPowFractionPrecision, testPowHalfPastTheRange, testPowHalfReference). M3 first survived the PR too, as near one the inverse lands on the grid with trailing zeros; the K1 case (d 1.23e-31, b = -1e40, error 0.752 of K1 N) was added and kills it. testsAfter 910 is the full forge suite at a9f6f93.",
1013+
"tool": "adversarial-mutation-test",
1014+
"skillVersion": "0.35.0",
1015+
"summary": {
1016+
"behaviours": 7,
1017+
"killedBefore": 2,
1018+
"killedAfter": 7,
1019+
"equivalent": 0,
1020+
"candidates": 0,
1021+
"confirmed": 0,
1022+
"testsBefore": 898,
1023+
"testsAfter": 910,
1024+
"filed": []
1025+
}
1026+
},
9621027
{
9631028
"timestamp": "2026-10-11T13:34:24Z",
9641029
"commit": "4ecd21232b7a94ce357032e4dbc8956f738e5975",
@@ -1000,5 +1065,26 @@
10001065
"testsAfter": 910,
10011066
"filed": []
10021067
}
1068+
},
1069+
{
1070+
"timestamp": "2026-10-11T16:10:59Z",
1071+
"commit": "3990c5e18165188ef99dbd9dc788a82d1e61d206",
1072+
"testsAfterCommit": "4b181ebb14c3ec9daa91b030475914b17a3263f1",
1073+
"publishedTag": "sol-v0.2.41",
1074+
"commitsAheadOfTag": 1,
1075+
"scope": "Issue #359: LibDecimalFloatImplementation.sqrt seeds Newton at a + E / b per exponent parity ((26e36, 12e37) for E in [1e75, 1e76), (82e35, 38e36) for E in [1e74, 1e75)) and runs four steps over E instead of the 2^125 shift step plus six. Before = the source commit with main's tests (plus the sqrt variants mirroring the new seed); probe suite: forge test --mc \"Sqrt|Pow\". After = the tests commit; probe suite: only the three new tests (testImplementationSqrtMainFuzz, testImplementationSqrtMainPackedFuzz, testImplementationSqrtMainSeedExtremes), which compare against the pre-#359 sqrt and the exact LibTestExactDecimal rule. Mutants: M01 three steps; M02/M03 parity constants swapped; M04-M07 a or E / b dropped per parity; M08 odd seed reads C; M09 odd seed unset; M10 even b a decade low; M11 even a 22e36 (d0 -0.144 at E = a b, past the -0.095 four steps tolerate); M12 odd b 30e36 (d0 0.31 at E = 1e75). Before 12/12 killed by existing tests (testSqrtReference, testSqrtMidpointEnds, testImplementationSqrtLowWordBorrow, testSqrtExact, testPowHalfReference among others); after 12/12 killed by the new tests alone (the probe named testImplementationSqrtMainSeedExtremes; its fail pattern does not capture fuzz counterexample lines). No adversarial findings: outputs equal the pre-#359 sqrt and the exact rule across the full int256 coefficient/exponent domain the implementation takes.",
1076+
"tool": "adversarial-mutation-test",
1077+
"skillVersion": "0.35.0",
1078+
"summary": {
1079+
"behaviours": 12,
1080+
"killedBefore": 12,
1081+
"killedAfter": 12,
1082+
"equivalent": 0,
1083+
"candidates": 0,
1084+
"confirmed": 0,
1085+
"testsBefore": 97,
1086+
"testsAfter": 3,
1087+
"filed": []
1088+
}
10031089
}
10041090
]

0 commit comments

Comments
 (0)