-
Notifications
You must be signed in to change notification settings - Fork 2
ceil #96
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
ceil #96
Changes from all commits
e966d5a
df8ad84
aeebef0
b006e6c
91d8a77
66fbd06
783dda0
cd44b06
e7c218c
69e81db
ca98517
10f8e2a
f07e43e
ee2857b
f9bbbe7
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 |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // SPDX-License-Identifier: CAL | ||
| pragma solidity =0.8.25; | ||
|
|
||
| import {LibDecimalFloat, Float} from "src/lib/LibDecimalFloat.sol"; | ||
| import {Test} from "forge-std/Test.sol"; | ||
| import {DecimalFloat} from "src/concrete/DecimalFloat.sol"; | ||
|
|
||
| contract DecimalFloatCeilTest is Test { | ||
| using LibDecimalFloat for Float; | ||
|
|
||
| function ceilExternal(Float a) external pure returns (Float) { | ||
| return a.ceil(); | ||
| } | ||
|
|
||
| function testCeilDeployed(Float a) external { | ||
| DecimalFloat deployed = new DecimalFloat(); | ||
|
|
||
|
Comment on lines
+15
to
+17
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) Optional: reuse a single DecimalFloat instance to reduce per-test deployment cost. Repeated new DecimalFloat() per fuzz case inflates gas/time. Consider a shared instance via setUp() unless test isolation requires fresh deployments. - DecimalFloat deployed = new DecimalFloat();
+ // Use a shared instance (initialized in setUp()).
+ DecimalFloat deployed = deployedInstance;Add once to the contract: DecimalFloat internal deployedInstance;
function setUp() public {
deployedInstance = new DecimalFloat();
}🧰 Tools🪛 GitHub Actions: Git is clean[error] git diff --exit-code failed (exit code 1). Detected end-of-file newline issue: 'No newline at end of file' in test/src/concrete/DecimalFloat.ceil.t.sol. 🤖 Prompt for AI Agents |
||
| try this.ceilExternal(a) returns (Float b) { | ||
| Float deployedB = deployed.ceil(a); | ||
|
|
||
| assertEq(Float.unwrap(b), Float.unwrap(deployedB)); | ||
| } catch (bytes memory err) { | ||
| vm.expectRevert(err); | ||
| deployed.ceil(a); | ||
| } | ||
| } | ||
|
Comment on lines
+15
to
+26
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) Good parity test between library and deployed wrapper
Consider renaming ceilExternal to internal helper in a separate contract if you later expand tests, but current approach is fine. 🤖 Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,107 @@ | ||||||||||||||||||
| // SPDX-License-Identifier: CAL | ||||||||||||||||||
| pragma solidity =0.8.25; | ||||||||||||||||||
|
|
||||||||||||||||||
| import {LibDecimalFloat, Float} from "src/lib/LibDecimalFloat.sol"; | ||||||||||||||||||
| import {LibDecimalFloatImplementation} from "src/lib/implementation/LibDecimalFloatImplementation.sol"; | ||||||||||||||||||
|
|
||||||||||||||||||
| import {Test, console2} from "forge-std/Test.sol"; | ||||||||||||||||||
|
|
||||||||||||||||||
| contract LibDecimalFloatCeilTest is Test { | ||||||||||||||||||
| using LibDecimalFloat for Float; | ||||||||||||||||||
|
|
||||||||||||||||||
| function testCeilNotReverts(Float float) external pure { | ||||||||||||||||||
| float.ceil(); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| function checkCeil( | ||||||||||||||||||
| int256 signedCoefficient, | ||||||||||||||||||
| int256 exponent, | ||||||||||||||||||
| int256 expectedSignedCoefficient, | ||||||||||||||||||
| int256 expectedExponent | ||||||||||||||||||
| ) internal pure { | ||||||||||||||||||
| (signedCoefficient, exponent) = | ||||||||||||||||||
| LibDecimalFloat.ceil(LibDecimalFloat.packLossless(signedCoefficient, exponent)).unpack(); | ||||||||||||||||||
|
|
||||||||||||||||||
| if (!LibDecimalFloatImplementation.eq(signedCoefficient, exponent, expectedSignedCoefficient, expectedExponent)) | ||||||||||||||||||
| { | ||||||||||||||||||
| console2.log("signedCoefficient", signedCoefficient); | ||||||||||||||||||
| console2.log("exponent", exponent); | ||||||||||||||||||
| console2.log("expectedSignedCoefficient", expectedSignedCoefficient); | ||||||||||||||||||
| console2.log("expectedExponent", expectedExponent); | ||||||||||||||||||
| revert("Ceil check failed"); | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /// Every non negative exponent is identity for ceil. | ||||||||||||||||||
| function testCeilNonNegative(int224 x, int256 exponent) external pure { | ||||||||||||||||||
| exponent = bound(exponent, 0, type(int32).max); | ||||||||||||||||||
| checkCeil(x, exponent, x, exponent); | ||||||||||||||||||
| } | ||||||||||||||||||
|
thedavidmeister marked this conversation as resolved.
|
||||||||||||||||||
|
|
||||||||||||||||||
| /// If the exponent is less than -76 then the ceil is 1 if x is positive, | ||||||||||||||||||
| /// or 0 if x is negative. | ||||||||||||||||||
| function testCeilLessThanMin(int224 x, int256 exponent) external pure { | ||||||||||||||||||
| exponent = bound(exponent, type(int32).min, -77); | ||||||||||||||||||
| if (x <= 0) { | ||||||||||||||||||
| checkCeil(x, exponent, 0, exponent); | ||||||||||||||||||
| } else { | ||||||||||||||||||
| checkCeil(x, exponent, 1, 0); | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
thedavidmeister marked this conversation as resolved.
thedavidmeister marked this conversation as resolved.
|
||||||||||||||||||
|
|
||||||||||||||||||
| /// For exponents [-76,-1] the ceil is the + 1. | ||||||||||||||||||
| function testCeilInRange(int224 x, int256 exponent) external pure { | ||||||||||||||||||
| exponent = bound(exponent, -76, -1); | ||||||||||||||||||
| int256 scale = int256(10 ** uint256(-exponent)); | ||||||||||||||||||
|
Comment on lines
+52
to
+55
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) Clarify docstring for the in-range behavior Doc is truncated. Suggest explicit statement of the rule used below. - /// For exponents [-76,-1] the ceil is the + 1.
+ /// For exponents in [-76, -1], ceil(x) = characteristic + 1 iff mantissa > 0; otherwise ceil(x) = characteristic.📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
|
|
||||||||||||||||||
| int256 characteristic = x / scale; | ||||||||||||||||||
| if (characteristic == 0) { | ||||||||||||||||||
| if (x > 0) { | ||||||||||||||||||
| // If the characteristic is 0 and x is positive then the ceil is 1. | ||||||||||||||||||
| checkCeil(x, exponent, 1, 0); | ||||||||||||||||||
| } else { | ||||||||||||||||||
| // If the characteristic is 0 and x is negative then the ceil is 0. | ||||||||||||||||||
| checkCeil(x, exponent, 0, exponent); | ||||||||||||||||||
| } | ||||||||||||||||||
| } else { | ||||||||||||||||||
| // If the characteristic is non-zero then we can just add 1 to it | ||||||||||||||||||
| // if the mantissa is non-zero. | ||||||||||||||||||
| int256 mantissa = x % scale; | ||||||||||||||||||
| if (mantissa > 0) { | ||||||||||||||||||
| // If the mantissa is greater than 0, we need to add 1 to | ||||||||||||||||||
| // the characteristic to get the ceiling. | ||||||||||||||||||
| characteristic += 1; | ||||||||||||||||||
| } | ||||||||||||||||||
| checkCeil(x, exponent, characteristic * scale, exponent); | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /// Examples | ||||||||||||||||||
| function testCeilExamples() external pure { | ||||||||||||||||||
| checkCeil(123456789, 0, 123456789, 0); | ||||||||||||||||||
| checkCeil(123456789, -1, 12345679000000000000000000000000000000000000000000000000000000000000, -60); | ||||||||||||||||||
| checkCeil(123456789, -2, 12345680000000000000000000000000000000000000000000000000000000000000, -61); | ||||||||||||||||||
| checkCeil(123456789, -3, 12345700000000000000000000000000000000000000000000000000000000000000, -62); | ||||||||||||||||||
| checkCeil(123456789, -4, 12346000000000000000000000000000000000000000000000000000000000000000, -63); | ||||||||||||||||||
| checkCeil(123456789, -5, 12350000000000000000000000000000000000000000000000000000000000000000, -64); | ||||||||||||||||||
| checkCeil(123456789, -6, 12400000000000000000000000000000000000000000000000000000000000000000, -65); | ||||||||||||||||||
| checkCeil(123456789, -7, 13000000000000000000000000000000000000000000000000000000000000000000, -66); | ||||||||||||||||||
| checkCeil(123456789, -8, 2000000000000000000000000000000000000000000000000000000000000000000, -66); | ||||||||||||||||||
| checkCeil(123456789, -9, 1, 0); | ||||||||||||||||||
| checkCeil(123456789, -10, 1, 0); | ||||||||||||||||||
| checkCeil(123456789, -11, 1, 0); | ||||||||||||||||||
| checkCeil(type(int224).max, 0, type(int224).max, 0); | ||||||||||||||||||
| checkCeil(type(int224).min, 0, type(int224).min, 0); | ||||||||||||||||||
| checkCeil(2.5e37, -37, 3e66, -66); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /// Test some zeros. | ||||||||||||||||||
| function testCeilZero(int32 exponent) external pure { | ||||||||||||||||||
| Float wrapZero = Float.wrap(0); | ||||||||||||||||||
| Float packZeroBasic = LibDecimalFloat.packLossless(0, 0); | ||||||||||||||||||
| Float packZero = LibDecimalFloat.packLossless(0, exponent); | ||||||||||||||||||
| assertTrue(wrapZero.ceil().eq(packZero)); | ||||||||||||||||||
| assertTrue(wrapZero.ceil().eq(packZeroBasic)); | ||||||||||||||||||
| assertEq(Float.unwrap(wrapZero.ceil()), Float.unwrap(packZeroBasic)); | ||||||||||||||||||
| } | ||||||||||||||||||
|
thedavidmeister marked this conversation as resolved.
|
||||||||||||||||||
| } | ||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.