-
Notifications
You must be signed in to change notification settings - Fork 2
2025 08 13 maximize moar #99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3453a4b
c8e9540
a006a0e
75587bb
344960d
2e5b32c
f58d8a7
06eadab
f6991f4
3ed206d
bc8851a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -306,7 +306,22 @@ library LibDecimalFloatImplementation { | |||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // The actual addition step. | ||||||||||||||||||||||||||||||||||||||||
| unchecked { | ||||||||||||||||||||||||||||||||||||||||
| signedCoefficientA += signedCoefficientB; | ||||||||||||||||||||||||||||||||||||||||
| int256 c = signedCoefficientA + signedCoefficientB; | ||||||||||||||||||||||||||||||||||||||||
| bool didOverflow; | ||||||||||||||||||||||||||||||||||||||||
| assembly ("memory-safe") { | ||||||||||||||||||||||||||||||||||||||||
| let sameSignAB := iszero(shr(0xff, xor(signedCoefficientA, signedCoefficientB))) | ||||||||||||||||||||||||||||||||||||||||
| let sameSignAC := iszero(shr(0xff, xor(signedCoefficientA, c))) | ||||||||||||||||||||||||||||||||||||||||
| didOverflow := and(sameSignAB, iszero(sameSignAC)) | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| // Be careful to handle overflow. | ||||||||||||||||||||||||||||||||||||||||
| if (didOverflow) { | ||||||||||||||||||||||||||||||||||||||||
| signedCoefficientA /= 10; | ||||||||||||||||||||||||||||||||||||||||
| signedCoefficientB /= 10; | ||||||||||||||||||||||||||||||||||||||||
| exponentA += 1; | ||||||||||||||||||||||||||||||||||||||||
| signedCoefficientA += signedCoefficientB; | ||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||
| signedCoefficientA = c; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
thedavidmeister marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||
| return (signedCoefficientA, exponentA); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -527,17 +542,9 @@ library LibDecimalFloatImplementation { | |||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| int256 initialExponent = exponent; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (signedCoefficient / 1e76 != 0) { | ||||||||||||||||||||||||||||||||||||||||
| signedCoefficient /= 10; | ||||||||||||||||||||||||||||||||||||||||
| exponent += 1; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (exponent < initialExponent) { | ||||||||||||||||||||||||||||||||||||||||
| revert ExponentOverflow(signedCoefficient, exponent); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| // Check if already maximized before dropping into a block full of | ||||||||||||||||||||||||||||||||||||||||
| // jumps. | ||||||||||||||||||||||||||||||||||||||||
| else if (signedCoefficient / 1e75 == 0) { | ||||||||||||||||||||||||||||||||||||||||
| if (signedCoefficient / 1e75 == 0) { | ||||||||||||||||||||||||||||||||||||||||
| if (signedCoefficient / 1e38 == 0) { | ||||||||||||||||||||||||||||||||||||||||
| signedCoefficient *= 1e38; | ||||||||||||||||||||||||||||||||||||||||
| exponent -= 38; | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -562,10 +569,19 @@ library LibDecimalFloatImplementation { | |||||||||||||||||||||||||||||||||||||||
| signedCoefficient *= 10; | ||||||||||||||||||||||||||||||||||||||||
| exponent -= 1; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (initialExponent < exponent) { | ||||||||||||||||||||||||||||||||||||||||
| revert ExponentOverflow(signedCoefficient, exponent); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| // Maybe we can fit in one more OOM without overflow, but we won't | ||||||||||||||||||||||||||||||||||||||||
| // know until we try. This pushes us into [1e76,type(int256).max] and | ||||||||||||||||||||||||||||||||||||||||
| // [-type(int256).max,-1e76] ranges, if that's possible. | ||||||||||||||||||||||||||||||||||||||||
| int256 trySignedCoefficient = signedCoefficient * 10; | ||||||||||||||||||||||||||||||||||||||||
| if (signedCoefficient == trySignedCoefficient / 10) { | ||||||||||||||||||||||||||||||||||||||||
| signedCoefficient = trySignedCoefficient; | ||||||||||||||||||||||||||||||||||||||||
| exponent -= 1; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+574
to
+581
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Use bound check instead of mul-then-div for overflow probe (micro-gas + clarity) The current try-multiply-then-divide round-trip is correct but slightly opaque and does an unnecessary multiply when it will overflow. A clearer and cheaper pattern is to pre-check bounds. Apply this refactor: - int256 trySignedCoefficient = signedCoefficient * 10;
- if (signedCoefficient == trySignedCoefficient / 10) {
- signedCoefficient = trySignedCoefficient;
- exponent -= 1;
- }
+ // Safe to multiply by 10 without overflow?
+ if (
+ signedCoefficient <= type(int256).max / 10 &&
+ signedCoefficient >= type(int256).min / 10
+ ) {
+ signedCoefficient *= 10;
+ exponent -= 1;
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i doubt it is cheaper as
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @thedavidmeister You're absolutely right about the 🐰 ✏️ Learnings added
🧠 Learnings used |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (initialExponent < exponent) { | ||||||||||||||||||||||||||||||||||||||||
| revert ExponentOverflow(signedCoefficient, exponent); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return (signedCoefficient, exponent); | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -799,7 +815,7 @@ library LibDecimalFloatImplementation { | |||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // If the exponent is less than -76, the characteristic is 0. | ||||||||||||||||||||||||||||||||||||||||
| // and the mantissa is the number itself. | ||||||||||||||||||||||||||||||||||||||||
| // and the mantissa is the whole coefficient. | ||||||||||||||||||||||||||||||||||||||||
| if (exponent < -76) { | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+818
to
819
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Comment fix improves clarity Updating the note to “mantissa is the whole coefficient” precisely matches the implementation returning (0, signedCoefficient) for exponent < -76. If you want, mirror this clarification in the function’s NatSpec for consistency. 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||
| return (0, signedCoefficient); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,49 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // SPDX-License-Identifier: CAL | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pragma solidity =0.8.25; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import {Test} from "forge-std/Test.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import {LibDecimalFloatImplementation} from "src/lib/implementation/LibDecimalFloatImplementation.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contract LibDecimalFloatImplementationCharacteristicMantissaTest is Test { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function checkCharacteristicMantissa( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int256 signedCoefficient, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int256 exponent, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int256 expectedCharacteristic, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int256 expectedMantissa | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) internal pure { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (int256 actualCharacteristic, int256 actualMantissa) = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LibDecimalFloatImplementation.characteristicMantissa(signedCoefficient, exponent); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertEq(actualCharacteristic, expectedCharacteristic, "Characteristic mismatch"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertEq(actualMantissa, expectedMantissa, "Mantissa mismatch"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+9
to
+20
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Augment helper with invariants to harden correctness On top of golden-value checks, assert structural invariants (decomposition, bounds, divisibility by scale) for exponent ranges where they’re well-defined. This catches regressions without duplicating test cases. Apply this diff to extend the helper: ) internal pure {
(int256 actualCharacteristic, int256 actualMantissa) =
LibDecimalFloatImplementation.characteristicMantissa(signedCoefficient, exponent);
assertEq(actualCharacteristic, expectedCharacteristic, "Characteristic mismatch");
assertEq(actualMantissa, expectedMantissa, "Mantissa mismatch");
+ // Invariants:
+ // - Only meaningful for exponent <= 0 (scale >= 1).
+ // - For exponent == -77, scale = 1e77 > int256.max so characteristic must be 0 and mantissa == coefficient.
+ if (exponent <= 0) {
+ if (exponent == -77) {
+ assertEq(actualCharacteristic, 0, "Characteristic at -77 must be 0");
+ assertEq(actualMantissa, signedCoefficient, "Mantissa at -77 must equal coefficient");
+ } else {
+ // For -76..0, 10**(-exponent) fits in int256.
+ uint256 scaleU = 10 ** uint256(uint256(-exponent)); // <= 1e76
+ int256 scale = int256(scaleU);
+
+ // Decomposition invariant
+ assertEq(actualCharacteristic + actualMantissa, signedCoefficient, "Decomposition invariant");
+ // Characteristic is a multiple of scale
+ assertEq(actualCharacteristic % scale, 0, "Characteristic must be multiple of scale");
+ // Mantissa magnitude bound: -scale < m < scale
+ assertTrue(actualMantissa > -scale && actualMantissa < scale, "Mantissa magnitude bound");
+ // Mantissa sign follows coefficient when non-zero
+ if (actualMantissa != 0) {
+ assertEq(actualMantissa > 0, signedCoefficient > 0, "Mantissa sign follows coefficient");
+ }
+ }
+ }
}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function testCharacteristicMantissaExamples() public pure { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(0, 0, 0, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(0, 1, 0, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(5.4304950862250382e16, -16, 5e16, 4304950862250382); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(-5.4304950862250382e16, -16, -5e16, -0.4304950862250382e16); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(5.4304950862250382e16, -76, 0, 5.4304950862250382e16); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(-5.4304950862250382e16, -76, 0, -5.4304950862250382e16); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Exact multiple => zero mantissa | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(5e16, -16, 5e16, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(-5e16, -16, -5e16, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Off-by-one around the multiple | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(5e16 + 1, -16, 5e16, 1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(-5e16 - 1, -16, -5e16, -1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Boundary at exponent -76 (scale = 1e76) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(1e76, -76, 1e76, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(1e76 + 1, -76, 1e76, 1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(-1e76, -76, -1e76, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(-1e76 - 1, -76, -1e76, -1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Beyond boundary at exponent -77 (scale > int256.max): characteristic must be 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(1, -77, 0, 1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkCharacteristicMantissa(-1, -77, 0, -1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+45
to
+47
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Cover exponent < -77 as well (-78) to nail down “always zero characteristic” region Given the documented semantics, exponents below -77 should behave the same as -77. Add a quick pair to make that explicit. // Beyond boundary at exponent -77 (scale > int256.max): characteristic must be 0
checkCharacteristicMantissa(1, -77, 0, 1);
checkCharacteristicMantissa(-1, -77, 0, -1);
+ // And below -77, the same semantics hold
+ checkCharacteristicMantissa(1, -78, 0, 1);
+ checkCharacteristicMantissa(-1, -78, 0, -1);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Avoid magic numbers: centralize the unpacked “one” as a named constant/helper
The pair (1e76, -76) is a magic number here and appears in tests as well. Consider introducing a single source of truth for the unpacked “one” to improve readability and reduce future churn if the normalization boundary shifts again.
Example approach (outside this file, in LibDecimalFloatImplementation.sol or a shared constants file):
Then here:
🤖 Prompt for AI Agents