diff --git a/.gas-snapshot b/.gas-snapshot index e38edae6..e17fc991 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,72 +1,112 @@ -LibDecimalFloatAbsTest:testAbsMinValue(int256) (runs: 2054, μ: 4419, ~: 4419) -LibDecimalFloatAbsTest:testAbsNegative(int256,int256) (runs: 2055, μ: 9920, ~: 10164) -LibDecimalFloatAbsTest:testAbsNonNegative(int256,int256) (runs: 2055, μ: 9033, ~: 8691) -LibDecimalFloatCompareTest:testCompareOne() (gas: 5610) -LibDecimalFloatCompareTest:testCompareOnePointSix() (gas: 4430) -LibDecimalFloatCompareTest:testCompareTen() (gas: 4939) +LibDecimalFloatAbsTest:testAbsMinValue(int256) (runs: 5108, μ: 4419, ~: 4419) +LibDecimalFloatAbsTest:testAbsNegative(int256,int256) (runs: 5109, μ: 9914, ~: 10164) +LibDecimalFloatAbsTest:testAbsNonNegative(int256,int256) (runs: 5109, μ: 9040, ~: 8691) LibDecimalFloatDecimalAddTest:testAdd123456789987654321() (gas: 6203) LibDecimalFloatDecimalAddTest:testAdd123456789e9987654321() (gas: 6255) -LibDecimalFloatDecimalAddTest:testAddNeverRevert(int256,int256,int256,int256) (runs: 2055, μ: 14171, ~: 14075) +LibDecimalFloatDecimalAddTest:testAddNeverRevert(int256,int256,int256,int256) (runs: 5109, μ: 14149, ~: 14075) LibDecimalFloatDecimalAddTest:testAddOneOneNotNormalized() (gas: 5818) LibDecimalFloatDecimalAddTest:testAddOneOnePreNormalized() (gas: 4250) LibDecimalFloatDecimalAddTest:testAddOneZero() (gas: 3688) -LibDecimalFloatDecimalAddTest:testAddSameExponentSameCoefficient(int256,int256) (runs: 2055, μ: 6413, ~: 6424) +LibDecimalFloatDecimalAddTest:testAddSameExponentSameCoefficient(int256,int256) (runs: 5109, μ: 6415, ~: 6427) LibDecimalFloatDecimalAddTest:testAddZero() (gas: 3664) -LibDecimalFloatDecimalAddTest:testAddZeroAnyExponent(int128) (runs: 2055, μ: 9311, ~: 9245) +LibDecimalFloatDecimalAddTest:testAddZeroAnyExponent(int128) (runs: 5109, μ: 9310, ~: 9245) LibDecimalFloatDecimalAddTest:testAddZeroOne() (gas: 3686) -LibDecimalFloatDecimalAddTest:testAddZeroToAnyNonZero(int256,int256,int256) (runs: 2054, μ: 14297, ~: 14176) +LibDecimalFloatDecimalAddTest:testAddZeroToAnyNonZero(int256,int256,int256) (runs: 5108, μ: 14299, ~: 14243) LibDecimalFloatDecimalAddTest:testAddingSmallToLargeReturnsLargeExamples() (gas: 19289) -LibDecimalFloatDecimalAddTest:testAddingSmallToLargeReturnsLargeFuzz(int256,int256,int256,int256) (runs: 2050, μ: 18699, ~: 18758) +LibDecimalFloatDecimalAddTest:testAddingSmallToLargeReturnsLargeFuzz(int256,int256,int256,int256) (runs: 5100, μ: 18700, ~: 18773) LibDecimalFloatDecimalAddTest:testGasAddOne() (gas: 944) LibDecimalFloatDecimalAddTest:testGasAddZero() (gas: 382) -LibDecimalFloatDecimalTest:testFixedDecimalRoundTripLossless(uint256,uint8) (runs: 2055, μ: 10145, ~: 10196) +LibDecimalFloatDecimalTest:testFixedDecimalRoundTripLossless(uint256,uint8) (runs: 5109, μ: 10148, ~: 10196) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyComplicated() (gas: 1022048) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyNormalizedMax() (gas: 760206) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyNormalizedMaxPlusOne() (gas: 866032) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOne() (gas: 975616) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOneMillion() (gas: 952412) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOverflow() (gas: 838681) -LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateOne(uint256,uint8) (runs: 2055, μ: 9551, ~: 7195) -LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateZero(uint256,uint8) (runs: 2055, μ: 8542, ~: 7207) -LibDecimalFloatDecimalTest:testToFixedDecimalLosslessScaleUp(int256,int256,uint8) (runs: 2052, μ: 16001, ~: 16228) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyExponentOverflow(int256,int256,uint8) (runs: 2055, μ: 14938, ~: 14718) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyIdentity(int256,uint8) (runs: 2055, μ: 10109, ~: 9778) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyNegative(int256,int256,uint8) (runs: 2055, μ: 9916, ~: 10161) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyScaleUpOverflow(int256,int256,uint8) (runs: 2051, μ: 13915, ~: 14172) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncate(int256,int256,uint8) (runs: 2055, μ: 14458, ~: 14188) +LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateOne(uint256,uint8) (runs: 5109, μ: 9541, ~: 7195) +LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateZero(uint256,uint8) (runs: 5109, μ: 8537, ~: 7207) +LibDecimalFloatDecimalTest:testToFixedDecimalLosslessScaleUp(int256,int256,uint8) (runs: 5103, μ: 15985, ~: 15974) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyExponentOverflow(int256,int256,uint8) (runs: 5109, μ: 14953, ~: 14718) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyIdentity(int256,uint8) (runs: 5109, μ: 10117, ~: 9778) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyNegative(int256,int256,uint8) (runs: 5109, μ: 9905, ~: 10161) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyScaleUpOverflow(int256,int256,uint8) (runs: 5102, μ: 13918, ~: 14172) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncate(int256,int256,uint8) (runs: 5109, μ: 14472, ~: 14190) LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncateLossless() (gas: 14500) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyUnderflow(int256,int256,uint8) (runs: 2055, μ: 13700, ~: 13580) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyZero(int256,uint8) (runs: 2055, μ: 4575, ~: 4575) -LibDecimalFloatDivideTest:testDivide1Over3() (gas: 6240) -LibDecimalFloatDivideTest:testDivide1Over3Gas0() (gas: 679) -LibDecimalFloatDivideTest:testDivide1Over3Gas10() (gas: 6248) -LibDecimalFloatDivideTest:testDivide1Over9Over1Over3() (gas: 9610) -LibDecimalFloatDivideTest:testDivide1e18Over3() (gas: 5249) -LibDecimalFloatDivideTest:testDivideNegative1Over3() (gas: 6324) -LibDecimalFloatDivideTest:testDivideOOMs5and2() (gas: 3928) -LibDecimalFloatDivideTest:testDivideOOMsOverTen() (gas: 4952) -LibDecimalFloatDivideTest:testDivideTenOverOOMs() (gas: 4862) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyUnderflow(int256,int256,uint8) (runs: 5109, μ: 13713, ~: 13580) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyZero(int256,uint8) (runs: 5109, μ: 4575, ~: 4575) +LibDecimalFloatDivideTest:testDivide1Over3() (gas: 6420) +LibDecimalFloatDivideTest:testDivide1Over3Gas0() (gas: 761) +LibDecimalFloatDivideTest:testDivide1Over3Gas10() (gas: 7068) +LibDecimalFloatDivideTest:testDivide1Over9Over1Over3() (gas: 9856) +LibDecimalFloatDivideTest:testDivide1e18Over3() (gas: 6148) +LibDecimalFloatDivideTest:testDivideNegative1Over3() (gas: 6490) +LibDecimalFloatDivideTest:testDivideOOMs5and2() (gas: 4827) +LibDecimalFloatDivideTest:testDivideOOMsOverTen() (gas: 5873) +LibDecimalFloatDivideTest:testDivideTenOverOOMs() (gas: 5738) +LibDecimalFloatDivideTest:testUnnormalizedThreesDivision0(int256,int256) (runs: 113, μ: 23628114, ~: 23628366) +LibDecimalFloatEqTest:testEqGasAZero() (gas: 430) +LibDecimalFloatEqTest:testEqGasBZero() (gas: 473) +LibDecimalFloatEqTest:testEqGasBothZero() (gas: 450) +LibDecimalFloatEqTest:testEqGasDifferentSigns() (gas: 482) +LibDecimalFloatEqTest:testEqGasExponentDiffOverflow() (gas: 578) +LibDecimalFloatEqTest:testEqNotReverts(int256,int256,int256,int256) (runs: 5109, μ: 653, ~: 679) +LibDecimalFloatEqTest:testEqOneEAny(int256,int256) (runs: 5109, μ: 3416, ~: 3416) +LibDecimalFloatEqTest:testEqReference(int256,int256,int256,int256) (runs: 5109, μ: 9883, ~: 11437) +LibDecimalFloatEqTest:testEqX(int256) (runs: 5109, μ: 3392, ~: 3392) +LibDecimalFloatEqTest:testEqXEAnyVsXEAny(int256,int256,int256) (runs: 5107, μ: 4716, ~: 4714) +LibDecimalFloatEqTest:testEqXEqY(int256,int256,int256,int256) (runs: 5109, μ: 732, ~: 753) +LibDecimalFloatEqTest:testEqXNotY(int256,int256,int256,int256) (runs: 5107, μ: 3927, ~: 3953) +LibDecimalFloatEqTest:testEqXNotYExponents(int256,int256,int256,int256) (runs: 5109, μ: 4241, ~: 4321) +LibDecimalFloatEqTest:testEqZero(int256,int256) (runs: 5109, μ: 3440, ~: 3440) +LibDecimalFloatGtTest:testGtGasAZero() (gas: 429) +LibDecimalFloatGtTest:testGtGasBZero() (gas: 428) +LibDecimalFloatGtTest:testGtGasBothZero() (gas: 452) +LibDecimalFloatGtTest:testGtGasDifferentSigns() (gas: 430) +LibDecimalFloatGtTest:testGtGasExponentDiffOverflow() (gas: 578) +LibDecimalFloatGtTest:testGtOneEAny(int256,int256) (runs: 5109, μ: 3443, ~: 3443) +LibDecimalFloatGtTest:testGtReference(int256,int256,int256,int256) (runs: 5109, μ: 9876, ~: 11407) +LibDecimalFloatGtTest:testGtX(int256) (runs: 5109, μ: 3417, ~: 3417) +LibDecimalFloatGtTest:testGtXEAnyVsXEAny(int256,int256,int256) (runs: 5109, μ: 9742, ~: 9530) +LibDecimalFloatGtTest:testGtXEAnyVsXEAnyNegative(int256,int256,int256) (runs: 5109, μ: 10324, ~: 10570) +LibDecimalFloatGtTest:testGtXNotY(int256,int256,int256,int256) (runs: 5109, μ: 4207, ~: 4286) +LibDecimalFloatGtTest:testGtXPositiveYNegative(int256,int256,int256,int256) (runs: 5109, μ: 12894, ~: 12801) +LibDecimalFloatGtTest:testGtXPositiveYZero(int256,int256,int256) (runs: 5109, μ: 9465, ~: 9255) +LibDecimalFloatGtTest:testGtZero(int256,int256) (runs: 5109, μ: 3465, ~: 3465) LibDecimalFloatInvTest:testInvGas0() (gas: 734) -LibDecimalFloatInvTest:testInvReference(int256,int256) (runs: 2054, μ: 13005, ~: 13131) +LibDecimalFloatInvTest:testInvReference(int256,int256) (runs: 5107, μ: 13016, ~: 13131) LibDecimalFloatInvTest:testInvSlowGas0() (gas: 755) LibDecimalFloatLog10Test:testExactLogs() (gas: 19667) +LibDecimalFloatLtTest:testLtGasAZero() (gas: 450) +LibDecimalFloatLtTest:testLtGasBZero() (gas: 472) +LibDecimalFloatLtTest:testLtGasBothZero() (gas: 451) +LibDecimalFloatLtTest:testLtGasDifferentSigns() (gas: 473) +LibDecimalFloatLtTest:testLtGasExponentDiffOverflow() (gas: 535) +LibDecimalFloatLtTest:testLtNegativeVsPositive(int256,int256,int256,int256) (runs: 5109, μ: 12879, ~: 12780) +LibDecimalFloatLtTest:testLtNegativeVsZero(int256,int256,int256) (runs: 5109, μ: 10028, ~: 10276) +LibDecimalFloatLtTest:testLtOneEAny(int256,int256) (runs: 5109, μ: 3465, ~: 3465) +LibDecimalFloatLtTest:testLtReference(int256,int256,int256,int256) (runs: 5109, μ: 9901, ~: 11454) +LibDecimalFloatLtTest:testLtVsEqualVsGt(int256,int256,int256,int256) (runs: 5109, μ: 4258, ~: 4332) +LibDecimalFloatLtTest:testLtX(int256) (runs: 5109, μ: 3438, ~: 3438) +LibDecimalFloatLtTest:testLtXEAnyVsXEAny(int256,int256,int256) (runs: 5109, μ: 9764, ~: 9552) +LibDecimalFloatLtTest:testLtXEAnyVsXEAnyNegative(int256,int256,int256) (runs: 5109, μ: 10303, ~: 10548) +LibDecimalFloatLtTest:testLtZero(int256,int256) (runs: 5109, μ: 3442, ~: 3442) LibDecimalFloatMixedTest:testDivide1Over3() (gas: 7213) LibDecimalFloatMultiplyTest:testMultiply123456789987654321() (gas: 3720) -LibDecimalFloatMultiplyTest:testMultiply123456789987654321WithExponents(int128,int128) (runs: 2055, μ: 13188, ~: 13269) +LibDecimalFloatMultiplyTest:testMultiply123456789987654321WithExponents(int128,int128) (runs: 5109, μ: 13184, ~: 13269) LibDecimalFloatMultiplyTest:testMultiply1e181e19() (gas: 3721) LibDecimalFloatMultiplyTest:testMultiplyGasOne() (gas: 382) LibDecimalFloatMultiplyTest:testMultiplyGasZero() (gas: 348) -LibDecimalFloatMultiplyTest:testMultiplyNotRevertAnyExpectation(int256,int256,int256,int256) (runs: 2055, μ: 13892, ~: 13096) +LibDecimalFloatMultiplyTest:testMultiplyNotRevertAnyExpectation(int256,int256,int256,int256) (runs: 5109, μ: 13910, ~: 13097) LibDecimalFloatMultiplyTest:testMultiplyOneOne() (gas: 3697) LibDecimalFloatMultiplyTest:testMultiplyOneZero() (gas: 3663) LibDecimalFloatMultiplyTest:testMultiplyZero0Exponent() (gas: 3619) -LibDecimalFloatMultiplyTest:testMultiplyZeroAnyExponent(int64,int64) (runs: 2055, μ: 3907, ~: 3907) +LibDecimalFloatMultiplyTest:testMultiplyZeroAnyExponent(int64,int64) (runs: 5109, μ: 3907, ~: 3907) LibDecimalFloatMultiplyTest:testMultiplyZeroOne() (gas: 3620) -LibDecimalFloatPackTest:testNormalizedRoundTrip(int256,int256) (runs: 2055, μ: 11156, ~: 11057) -LibDecimalFloatPackTest:testPartsRoundTrip(int128,int128) (runs: 2055, μ: 4718, ~: 4718) -LibDecimalFloatSubTest:testMinusIsSubZero(int256,int256,int256) (runs: 2055, μ: 13219, ~: 13282) -LibDecimalFloatSubTest:testSubIsAdd(int256,int256,int256,int256) (runs: 2055, μ: 17626, ~: 17848) -LibDecimalFloatSubTest:testSubMinSignedValue(int256,int256,int256) (runs: 2055, μ: 17359, ~: 17268) +LibDecimalFloatPackTest:testNormalizedRoundTrip(int256,int256) (runs: 5109, μ: 11154, ~: 11057) +LibDecimalFloatPackTest:testPartsRoundTrip(int128,int128) (runs: 5109, μ: 4718, ~: 4718) +LibDecimalFloatSubTest:testMinusIsSubZero(int256,int256,int256) (runs: 5109, μ: 13217, ~: 13268) +LibDecimalFloatSubTest:testSubIsAdd(int256,int256,int256,int256) (runs: 5108, μ: 17589, ~: 17843) +LibDecimalFloatSubTest:testSubMinSignedValue(int256,int256,int256) (runs: 5109, μ: 17350, ~: 17236) LibLogTableBytesTest:testToBytesAntiLogTableDec() (gas: 158027) LibLogTableBytesTest:testToBytesAntiLogTableDecSmall() (gas: 160620) LibLogTableBytesTest:testToBytesLogTableDec() (gas: 141631) diff --git a/foundry.toml b/foundry.toml index b560a7a9..7edddf34 100644 --- a/foundry.toml +++ b/foundry.toml @@ -29,4 +29,4 @@ remappings = [ ] [fuzz] -runs = 2048 \ No newline at end of file +runs = 5096 \ No newline at end of file diff --git a/src/lib/LibDecimalFloat.sol b/src/lib/LibDecimalFloat.sol index 26abf53d..4abf03aa 100644 --- a/src/lib/LibDecimalFloat.sol +++ b/src/lib/LibDecimalFloat.sol @@ -22,13 +22,6 @@ import { EXPONENT_STEP_SIZE } from "./implementation/LibDecimalFloatImplementation.sol"; -/// @dev Returned by `compare` when the first operand is less than the second. -int256 constant COMPARE_LESS_THAN = -1; -/// @dev Returned by `compare` when the operands are equal. -int256 constant COMPARE_EQUAL = 0; -/// @dev Returned by `compare` when the first operand is greater than the second. -int256 constant COMPARE_GREATER_THAN = 1; - uint256 constant ADD_MAX_EXPONENT_DIFF = 37; /// @dev When normalizing a number, how far we "leap" when very far from @@ -575,45 +568,76 @@ library LibDecimalFloat { return (signedCoefficient, exponent); } - /// https://speleotrove.com/decimal/daops.html#refnumco - /// > compare takes two operands and compares their values numerically. If - /// > either operand is a special value then the general rules apply. No - /// > flags are set unless an operand is a signaling NaN. - /// > - /// > Otherwise, the operands are compared as follows. - /// > - /// > If the signs of the operands differ, a value representing each operand - /// > (’-1’ if the operand is less than zero, ’0’ if the operand is zero or - /// > negative zero, or ’1’ if the operand is greater than zero) is used in - /// > place of that operand for the comparison instead of the actual operand. - /// > - /// > The comparison is then effected by subtracting the second operand from - /// > the first and then returning a value according to the result of the - /// > subtraction: ’-1’ if the result is less than zero, ’0’ if the result is - /// > zero or negative zero, or ’1’ if the result is greater than zero. - /// > - /// > An implementation may use this operation ‘under the covers’ to - /// > implement a closed set of comparison operations - /// > (greater than, equal,etc.) if desired. It need not, in this case, - /// > expose the compare operation itself. - function compare(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) + /// Numeric equality for floats. + /// Two floats are equal if their numeric value is equal. + /// For example, 1e2, 10e1, and 100e0 are all equal. Also implies that 0eX + /// and 0eY are equal for all X and Y. + /// Any representable value can be equality checked without precision loss, + /// e.g. no normalization is done internally. + /// @param signedCoefficientA The signed coefficient of the first floating + /// point number. + /// @param exponentA The exponent of the first floating point number. + /// @param signedCoefficientB The signed coefficient of the second floating + /// point number. + /// @param exponentB The exponent of the second floating point number. + /// @return `true` if the two floats are equal, `false` otherwise. + function eq(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) internal pure - returns (int256) + returns (bool) { - // We don't support negative zero. - (signedCoefficientB, exponentB) = minus(signedCoefficientB, exponentB); - // We want the un-normalized result so that rounding doesn't affect the - // comparison. - (int256 signedCoefficient,) = add(signedCoefficientA, exponentA, signedCoefficientB, exponentB); - - if (signedCoefficient == 0) { - return COMPARE_EQUAL; - } else if (signedCoefficient < 0) { - return COMPARE_LESS_THAN; - } else { - return COMPARE_GREATER_THAN; - } + (signedCoefficientA, signedCoefficientB) = + LibDecimalFloatImplementation.compareRescale(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + + return signedCoefficientA == signedCoefficientB; + } + + /// Numeric less than for floats. + /// A float is less than another if its numeric value is less than the other. + /// For example, 1e2 is less than 1e3, and 1e2 is less than 2e2. + /// Any representable value can be compared without precision loss, e.g. no + /// normalization is done internally. + /// @param signedCoefficientA The signed coefficient of the first floating + /// point number. + /// @param exponentA The exponent of the first floating point number. + /// @param signedCoefficientB The signed coefficient of the second floating + /// point number. + /// @param exponentB The exponent of the second floating point number. + /// @return `true` if the first float is less than the second, `false` + /// otherwise. + function lt(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) + internal + pure + returns (bool) + { + (signedCoefficientA, signedCoefficientB) = + LibDecimalFloatImplementation.compareRescale(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + + return signedCoefficientA < signedCoefficientB; + } + + /// Numeric greater than for floats. + /// A float is greater than another if its numeric value is greater than the + /// other. For example, 1e3 is greater than 1e2, and 2e2 is greater than 1e2. + /// Any representable value can be compared without precision loss, e.g. no + /// normalization is done internally. + /// @param signedCoefficientA The signed coefficient of the first floating + /// point number. + /// @param exponentA The exponent of the first floating point number. + /// @param signedCoefficientB The signed coefficient of the second floating + /// point number. + /// @param exponentB The exponent of the second floating point number. + /// @return `true` if the first float is greater than the second, `false` + /// otherwise. + function gt(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) + internal + pure + returns (bool) + { + (signedCoefficientA, signedCoefficientB) = + LibDecimalFloatImplementation.compareRescale(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + + return signedCoefficientA > signedCoefficientB; } /// a^b = 10^(b * log10(a)) diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index 2e91ab25..dd41443e 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -100,4 +100,105 @@ library LibDecimalFloatImplementation { return (signedCoefficient, exponent); } } + + /// Rescale two floats so that they are possible to directly compare using + /// standard operators on the signed coefficient. + /// + /// There is no guarantee that the returned values somehow represent the + /// input values. The only guarantee is that comparing them directly will + /// give the same result as comparing the inputs as floats. + /// + /// https://speleotrove.com/decimal/daops.html#refnumco + /// > compare takes two operands and compares their values numerically. If + /// > either operand is a special value then the general rules apply. No + /// > flags are set unless an operand is a signaling NaN. + /// > + /// > Otherwise, the operands are compared as follows. + /// > + /// > If the signs of the operands differ, a value representing each operand + /// > (’-1’ if the operand is less than zero, ’0’ if the operand is zero or + /// > negative zero, or ’1’ if the operand is greater than zero) is used in + /// > place of that operand for the comparison instead of the actual operand. + /// > + /// > The comparison is then effected by subtracting the second operand from + /// > the first and then returning a value according to the result of the + /// > subtraction: ’-1’ if the result is less than zero, ’0’ if the result is + /// > zero or negative zero, or ’1’ if the result is greater than zero. + /// > + /// > An implementation may use this operation ‘under the covers’ to + /// > implement a closed set of comparison operations + /// > (greater than, equal,etc.) if desired. It need not, in this case, + /// > expose the compare operation itself. + function compareRescale(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) + internal + pure + returns (int256, int256) + { + unchecked { + // There are special cases where the signed coefficients can be + // compared directly, ignoring their exponents, without rescaling: + // - Either is zero + // - They have different signs + // - Their exponents are equal + { + bool noopRescale; + assembly ("memory-safe") { + noopRescale := + or( + or( + // Either is zero + or(iszero(signedCoefficientA), iszero(signedCoefficientB)), + // They have different signs + xor(slt(signedCoefficientA, 0), slt(signedCoefficientB, 0)) + ), + // Their exponents are equal + eq(exponentA, exponentB) + ) + } + if (noopRescale) { + return (signedCoefficientA, signedCoefficientB); + } + } + + bool didSwap = false; + if (exponentB > exponentA) { + int256 tmp = signedCoefficientA; + signedCoefficientA = signedCoefficientB; + signedCoefficientB = tmp; + + tmp = exponentA; + exponentA = exponentB; + exponentB = tmp; + + didSwap = true; + } + + int256 exponentDiff = exponentA - exponentB; + bool didOverflow; + assembly ("memory-safe") { + didOverflow := or(slt(exponentDiff, 0), sgt(exponentDiff, 76)) + } + if (didOverflow) { + if (didSwap) { + return (0, signedCoefficientA); + } else { + return (signedCoefficientA, 0); + } + } + int256 scale = int256(10 ** uint256(exponentDiff)); + int256 rescaled = signedCoefficientA * scale; + + if (rescaled / scale != signedCoefficientA) { + if (didSwap) { + return (0, signedCoefficientA); + } else { + return (signedCoefficientA, 0); + } + } else if (didSwap) { + return (signedCoefficientB, rescaled); + } else { + return (rescaled, signedCoefficientB); + } + } + } } diff --git a/test/lib/LibDecimalFloatSlow.sol b/test/lib/LibDecimalFloatSlow.sol index 72bec800..e2b1f975 100644 --- a/test/lib/LibDecimalFloatSlow.sol +++ b/test/lib/LibDecimalFloatSlow.sol @@ -40,4 +40,129 @@ library LibDecimalFloatSlow { function invSlow(int256 signedCoefficient, int256 exponent) internal pure returns (int256, int256) { return LibDecimalFloat.divide(1e37, -37, signedCoefficient, exponent); } + + function eqSlow(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) + internal + pure + returns (bool) + { + // If the exponents are the same we compare the coefficients. + if (exponentA == exponentB) { + return signedCoefficientA == signedCoefficientB; + } + + // Comparisons with zero ignore exponents. + if (signedCoefficientA == 0 || signedCoefficientB == 0) { + return signedCoefficientA == signedCoefficientB; + } + + unchecked { + int256 tmp = 0; + while (exponentA > exponentB) { + tmp = signedCoefficientA * 10; + if (tmp / 10 != signedCoefficientA) { + return false; + } + signedCoefficientA = tmp; + exponentA--; + } + + while (exponentB > exponentA) { + tmp = signedCoefficientB * 10; + if (tmp / 10 != signedCoefficientB) { + return false; + } + signedCoefficientB = tmp; + exponentB--; + } + } + + return eqSlow(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + } + + function gtSlow(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) + internal + pure + returns (bool) + { + // If the exponents are the same we compare the coefficients. + if (exponentA == exponentB) { + return signedCoefficientA > signedCoefficientB; + } + + // Comparisons with zero ignore exponents. + if (signedCoefficientA == 0 || signedCoefficientB == 0) { + return signedCoefficientA > signedCoefficientB; + } + + unchecked { + int256 tmp = 0; + while (exponentA > exponentB) { + tmp = signedCoefficientA * 10; + if (tmp / 10 != signedCoefficientA) { + // A overflowed so is huge in magnitude, it's gt everything + // if positive and lt everything if it's negative. + return signedCoefficientA > 0; + } + signedCoefficientA = tmp; + exponentA--; + } + + while (exponentB > exponentA) { + tmp = signedCoefficientB * 10; + if (tmp / 10 != signedCoefficientB) { + // B overflowed so is huge in magnitude, it's gt everything + // if positive and lt everything if it's negative. + return signedCoefficientB < 0; + } + signedCoefficientB = tmp; + exponentB--; + } + } + + return gtSlow(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + } + + function ltSlow(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) + internal + pure + returns (bool) + { + // If the exponents are the same we compare the coefficients. + if (exponentA == exponentB) { + return signedCoefficientA < signedCoefficientB; + } + + // Comparisons with zero ignore exponents. + if (signedCoefficientA == 0 || signedCoefficientB == 0) { + return signedCoefficientA < signedCoefficientB; + } + + unchecked { + int256 tmp = 0; + while (exponentA > exponentB) { + tmp = signedCoefficientA * 10; + if (tmp / 10 != signedCoefficientA) { + // A overflowed so is huge in magnitude, it's gt everything + // if positive and lt everything if it's negative. + return signedCoefficientA < 0; + } + signedCoefficientA = tmp; + exponentA--; + } + + while (exponentB > exponentA) { + tmp = signedCoefficientB * 10; + if (tmp / 10 != signedCoefficientB) { + // B overflowed so is huge in magnitude, it's gt everything + // if positive and lt everything if it's negative. + return signedCoefficientB > 0; + } + signedCoefficientB = tmp; + exponentB--; + } + } + + return ltSlow(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + } } diff --git a/test/src/LibDecimalFloat.add.t.sol b/test/src/LibDecimalFloat.add.t.sol index b66ff74f..c1f694ef 100644 --- a/test/src/LibDecimalFloat.add.t.sol +++ b/test/src/LibDecimalFloat.add.t.sol @@ -1,13 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity =0.8.25; -import { - LibDecimalFloat, - COMPARE_EQUAL, - EXPONENT_MIN, - EXPONENT_MAX, - ADD_MAX_EXPONENT_DIFF -} from "src/lib/LibDecimalFloat.sol"; +import {LibDecimalFloat, EXPONENT_MIN, EXPONENT_MAX, ADD_MAX_EXPONENT_DIFF} from "src/lib/LibDecimalFloat.sol"; import {LibDecimalFloatImplementation} from "src/lib/implementation/LibDecimalFloatImplementation.sol"; import {Test} from "forge-std/Test.sol"; diff --git a/test/src/LibDecimalFloat.compare.t.sol b/test/src/LibDecimalFloat.compare.t.sol deleted file mode 100644 index 2e770963..00000000 --- a/test/src/LibDecimalFloat.compare.t.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: CAL -pragma solidity =0.8.25; - -import {LibDecimalFloat, COMPARE_EQUAL, COMPARE_GREATER_THAN} from "src/lib/LibDecimalFloat.sol"; - -import {Test} from "forge-std/Test.sol"; - -contract LibDecimalFloatCompareTest is Test { - /// 1 == 1 - function testCompareOne() external pure { - int256 compare = LibDecimalFloat.compare(1, 0, 1, 0); - assertEq(compare, COMPARE_EQUAL); - } - - /// 10,0 == 1e38,-37 - function testCompareTen() external pure { - int256 compare = LibDecimalFloat.compare(10, 0, 1e38, -37); - assertEq(compare, COMPARE_EQUAL); - } - - /// 1.6e35,-35 > 1.25e37,-37 - function testCompareOnePointSix() external pure { - int256 compare = LibDecimalFloat.compare(1.6e35, -35, 1.25e37, -37); - assertEq(compare, COMPARE_GREATER_THAN); - } -} diff --git a/test/src/LibDecimalFloat.eq.t.sol b/test/src/LibDecimalFloat.eq.t.sol new file mode 100644 index 00000000..bbaa64d0 --- /dev/null +++ b/test/src/LibDecimalFloat.eq.t.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: CAL +pragma solidity =0.8.25; + +import {LibDecimalFloat} from "src/lib/LibDecimalFloat.sol"; + +import {LibDecimalFloatSlow} from "test/lib/LibDecimalFloatSlow.sol"; + +import {Test} from "forge-std/Test.sol"; + +contract LibDecimalFloatEqTest is Test { + function testEqReference(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) + external + pure + { + bool actual = LibDecimalFloat.eq(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + bool expected = LibDecimalFloatSlow.eqSlow(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + + assertEq(actual, expected); + } + + function testEqNotReverts(int256 x, int256 exponentX, int256 y, int256 exponentY) external pure { + LibDecimalFloat.eq(x, exponentX, y, exponentY); + } + + /// x == x + function testEqX(int256 x) external pure { + bool eq = LibDecimalFloat.eq(x, 0, x, 0); + assertTrue(eq); + } + + /// xeX == xeX + function testEqOneEAny(int256 x, int256 exponent) external pure { + bool eq = LibDecimalFloat.eq(x, exponent, x, exponent); + assertTrue(eq); + } + + /// xeX != xeY if X != Y && x != 0 + function testEqXEAnyVsXEAny(int256 x, int256 exponentX, int256 exponentY) external pure { + vm.assume(x != 0); + bool eq = LibDecimalFloat.eq(x, exponentX, x, exponentY); + + assertEq(eq, exponentX == exponentY); + + // Reverse the order. + eq = LibDecimalFloat.eq(x, exponentY, x, exponentX); + assertEq(eq, exponentX == exponentY); + } + + /// xeX == xeY if x == 0 + function testEqZero(int256 exponentX, int256 exponentY) external pure { + bool eq = LibDecimalFloat.eq(0, exponentX, 0, exponentY); + assertTrue(eq); + } + + /// xeX != yeY if x != y + function testEqXNotY(int256 x, int256 exponentX, int256 y, int256 exponentY) external pure { + vm.assume(x != y); + bool eq = LibDecimalFloat.eq(x, exponentX, y, exponentY); + assertTrue(!eq); + } + + /// xeX != yeY if xeX < xeY || xeX > xeY + function testEqXNotYExponents(int256 x, int256 exponentX, int256 y, int256 exponentY) external pure { + bool eq = LibDecimalFloat.eq(x, exponentX, y, exponentY); + bool lt = LibDecimalFloat.lt(x, exponentX, y, exponentY); + bool gt = LibDecimalFloat.gt(x, exponentX, y, exponentY); + + assertEq(eq, !lt && !gt); + } + + /// if xeX == yeY, then x / y == 10^(X - Y) || y / x == 10^(Y - X) + function testEqXEqY(int256 x, int256 exponentX, int256 y, int256 exponentY) external pure { + bool eq = LibDecimalFloat.eq(x, exponentX, y, exponentY); + + if (eq) { + if (x == y) { + assertTrue(exponentX == exponentY || x == 0); + } else if (y > x) { + assertTrue(exponentY < exponentX, "y > x but exponentY >= exponentX"); + assertTrue(exponentX - exponentY < 77, "y > x but exponentX - exponentY >= 77"); + assertEq(x / y, int256(10 ** uint256(exponentX - exponentY)), "y > x but x / y != 10^(X - Y)"); + assertEq(x % y, 0, "y > x but x % y != 0"); + } else { + assertTrue(exponentX < exponentY, "x < y but exponentX >= exponentY"); + assertTrue(exponentY - exponentX < 77, "x < y but exponentY - exponentX >= 77"); + assertEq(y / x, int256(10 ** uint256(exponentY - exponentX)), "x < y but y / x != 10^(Y - X)"); + assertEq(y % x, 0, "x < y but y % x != 0"); + } + } else { + if (x == y) { + assertTrue(exponentX != exponentY); + } + } + } + + function testEqGasDifferentSigns() external pure { + LibDecimalFloat.eq(1, 0, -1, 0); + } + + function testEqGasAZero() external pure { + LibDecimalFloat.eq(0, 0, 1, 0); + } + + function testEqGasBZero() external pure { + LibDecimalFloat.eq(1, 0, 0, 0); + } + + function testEqGasBothZero() external pure { + LibDecimalFloat.eq(0, 0, 0, 0); + } + + function testEqGasExponentDiffOverflow() external pure { + LibDecimalFloat.eq(1, type(int256).max, 1, type(int256).min); + } +} diff --git a/test/src/LibDecimalFloat.gt.t.sol b/test/src/LibDecimalFloat.gt.t.sol new file mode 100644 index 00000000..23b1f49f --- /dev/null +++ b/test/src/LibDecimalFloat.gt.t.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: CAL +pragma solidity =0.8.25; + +import {LibDecimalFloat} from "src/lib/LibDecimalFloat.sol"; + +import {LibDecimalFloatSlow} from "test/lib/LibDecimalFloatSlow.sol"; + +import {Test} from "forge-std/Test.sol"; + +contract LibDecimalFloatGtTest is Test { + function testGtReference(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) + external + pure + { + bool actual = LibDecimalFloat.gt(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + bool expected = LibDecimalFloatSlow.gtSlow(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + + assertEq(actual, expected); + } + + /// x !> x + function testGtX(int256 x) external pure { + bool gt = LibDecimalFloat.gt(x, 0, x, 0); + assertTrue(!gt); + } + + /// xeX !> xeX + function testGtOneEAny(int256 x, int256 exponent) external pure { + bool gt = LibDecimalFloat.gt(x, exponent, x, exponent); + assertTrue(!gt); + } + + /// xeX > xeY if X > Y && x > 0 + function testGtXEAnyVsXEAny(int256 x, int256 exponentA, int256 exponentB) external pure { + x = bound(x, 1, type(int256).max); + bool gt = LibDecimalFloat.gt(x, exponentA, x, exponentB); + + assertEq(gt, exponentA > exponentB); + + // Reverse the order. + gt = LibDecimalFloat.gt(x, exponentB, x, exponentA); + assertEq(gt, exponentB > exponentA); + } + + /// xeX > xeY if X < Y && x < 0 + function testGtXEAnyVsXEAnyNegative(int256 x, int256 exponentA, int256 exponentB) external pure { + x = bound(x, type(int256).min, -1); + bool gt = LibDecimalFloat.gt(x, exponentA, x, exponentB); + + assertEq(gt, exponentA < exponentB); + + // Reverse the order. + gt = LibDecimalFloat.gt(x, exponentB, x, exponentA); + assertEq(gt, exponentB < exponentA); + } + + /// xeX !> xeY if x == 0 + function testGtZero(int256 exponentA, int256 exponentB) external pure { + bool gt = LibDecimalFloat.gt(0, exponentA, 0, exponentB); + assertTrue(!gt); + } + + /// xeX > yeY if x >= 0 && y < 0 + function testGtXPositiveYNegative(int256 x, int256 exponentX, int256 y, int256 exponentY) external pure { + x = bound(x, 0, type(int256).max); + y = bound(y, type(int256).min, -1); + bool gt = LibDecimalFloat.gt(x, exponentX, y, exponentY); + assertTrue(gt); + + // Reverse the order. + gt = LibDecimalFloat.gt(y, exponentY, x, exponentX); + assertTrue(!gt); + } + + /// xeX > yeY if xeX != yeY && xeX !< yeY + function testGtXNotY(int256 x, int256 exponentX, int256 y, int256 exponentY) external pure { + bool gt = LibDecimalFloat.gt(x, exponentX, y, exponentY); + bool eq = LibDecimalFloat.eq(x, exponentX, y, exponentY); + bool lt = LibDecimalFloat.lt(x, exponentX, y, exponentY); + + assertEq(gt, !lt && !eq); + } + + /// xeX > yeY if xeX > 0 && yeY == 0 + function testGtXPositiveYZero(int256 x, int256 exponentX, int256 exponentZero) external pure { + x = bound(x, 1, type(int256).max); + bool gt = LibDecimalFloat.gt(x, exponentX, 0, exponentZero); + assertTrue(gt); + + // Reverse the order. + gt = LibDecimalFloat.gt(0, exponentZero, x, exponentX); + assertTrue(!gt); + } + + function testGtGasDifferentSigns() external pure { + LibDecimalFloat.gt(1, 0, -1, 0); + } + + function testGtGasAZero() external pure { + LibDecimalFloat.gt(0, 0, 1, 0); + } + + function testGtGasBZero() external pure { + LibDecimalFloat.gt(1, 0, 0, 0); + } + + function testGtGasBothZero() external pure { + LibDecimalFloat.gt(0, 0, 0, 0); + } + + function testGtGasExponentDiffOverflow() external pure { + LibDecimalFloat.gt(1, type(int256).max, 1, type(int256).min); + } +} diff --git a/test/src/LibDecimalFloat.log10.t.sol b/test/src/LibDecimalFloat.log10.t.sol index 5b2dd69a..3601da79 100644 --- a/test/src/LibDecimalFloat.log10.t.sol +++ b/test/src/LibDecimalFloat.log10.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity =0.8.25; -import {LibDecimalFloat, COMPARE_EQUAL} from "src/lib/LibDecimalFloat.sol"; +import {LibDecimalFloat} from "src/lib/LibDecimalFloat.sol"; import {Test, console} from "forge-std/Test.sol"; diff --git a/test/src/LibDecimalFloat.lt.t.sol b/test/src/LibDecimalFloat.lt.t.sol new file mode 100644 index 00000000..a26e461f --- /dev/null +++ b/test/src/LibDecimalFloat.lt.t.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: CAL +pragma solidity =0.8.25; + +import {LibDecimalFloat} from "src/lib/LibDecimalFloat.sol"; + +import {LibDecimalFloatSlow} from "test/lib/LibDecimalFloatSlow.sol"; + +import {Test} from "forge-std/Test.sol"; + +contract LibDecimalFloatLtTest is Test { + function testLtReference(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) + external + pure + { + bool actual = LibDecimalFloat.lt(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + bool expected = LibDecimalFloatSlow.ltSlow(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + + assertEq(actual, expected); + } + + /// x !< x + function testLtX(int256 x) external pure { + bool lt = LibDecimalFloat.lt(x, 0, x, 0); + assertTrue(!lt); + } + + /// xeX !< xeX + function testLtOneEAny(int256 x, int256 exponent) external pure { + bool lt = LibDecimalFloat.lt(x, exponent, x, exponent); + assertTrue(!lt); + } + + /// xeX < xeY if X < Y && x > 0 + function testLtXEAnyVsXEAny(int256 x, int256 exponentA, int256 exponentB) external pure { + x = bound(x, 1, type(int256).max); + bool lt = LibDecimalFloat.lt(x, exponentA, x, exponentB); + + assertEq(lt, exponentA < exponentB); + + // Reverse the order. + lt = LibDecimalFloat.lt(x, exponentB, x, exponentA); + assertEq(lt, exponentB < exponentA); + } + + /// xeX < xeY if X > Y && x < 0 + function testLtXEAnyVsXEAnyNegative(int256 x, int256 exponentA, int256 exponentB) external pure { + x = bound(x, type(int256).min, -1); + bool lt = LibDecimalFloat.lt(x, exponentA, x, exponentB); + + assertEq(lt, exponentA > exponentB); + + // Reverse the order. + lt = LibDecimalFloat.lt(x, exponentB, x, exponentA); + assertEq(lt, exponentB > exponentA); + } + + /// xeX !< xeY if x == 0 + function testLtZero(int256 exponentA, int256 exponentB) external pure { + bool lt = LibDecimalFloat.lt(0, exponentA, 0, exponentB); + assertTrue(!lt); + } + + /// xeX < yeY if x < 0 && y >= 0 + function testLtNegativeVsPositive( + int256 signedCoefficientNeg, + int256 exponentNeg, + int256 signedCoefficientPos, + int256 exponentPos + ) external pure { + signedCoefficientNeg = bound(signedCoefficientNeg, type(int256).min, -1); + signedCoefficientPos = bound(signedCoefficientPos, 0, type(int256).max); + + bool lt = LibDecimalFloat.lt(signedCoefficientNeg, exponentNeg, signedCoefficientPos, exponentPos); + assertTrue(lt); + + // Reverse the order. + lt = LibDecimalFloat.lt(signedCoefficientPos, exponentPos, signedCoefficientNeg, exponentNeg); + assertTrue(!lt); + } + + /// X < Y if Y !< X && X != Y + function testLtVsEqualVsGt(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) + external + pure + { + bool lt = LibDecimalFloat.lt(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + bool equal = LibDecimalFloat.eq(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + bool gt = LibDecimalFloat.gt(signedCoefficientA, exponentA, signedCoefficientB, exponentB); + + assertEq(lt, !equal && !gt); + } + + /// X < Y if X < 0 && Y == 0 + function testLtNegativeVsZero(int256 signedCoefficientNeg, int256 exponentNeg, int256 exponentZero) external pure { + signedCoefficientNeg = bound(signedCoefficientNeg, type(int256).min, -1); + + bool lt = LibDecimalFloat.lt(signedCoefficientNeg, exponentNeg, 0, exponentZero); + assertTrue(lt); + + // Reverse the order. + lt = LibDecimalFloat.lt(0, exponentZero, signedCoefficientNeg, exponentNeg); + assertTrue(!lt); + } + + function testLtGasDifferentSigns() external pure { + LibDecimalFloat.lt(1, 0, -1, 0); + } + + function testLtGasAZero() external pure { + LibDecimalFloat.lt(0, 0, 1, 0); + } + + function testLtGasBZero() external pure { + LibDecimalFloat.lt(1, 0, 0, 0); + } + + function testLtGasBothZero() external pure { + LibDecimalFloat.lt(0, 0, 0, 0); + } + + function testLtGasExponentDiffOverflow() external pure { + LibDecimalFloat.lt(1, type(int256).max, 1, type(int256).min); + } +} diff --git a/test/src/LibDecimalFloat.multiply.t.sol b/test/src/LibDecimalFloat.multiply.t.sol index a029f2a6..be4a0c8c 100644 --- a/test/src/LibDecimalFloat.multiply.t.sol +++ b/test/src/LibDecimalFloat.multiply.t.sol @@ -2,10 +2,7 @@ pragma solidity =0.8.25; import { - LibDecimalFloat, - COMPARE_EQUAL, - NORMALIZED_ZERO_SIGNED_COEFFICIENT, - NORMALIZED_ZERO_EXPONENT + LibDecimalFloat, NORMALIZED_ZERO_SIGNED_COEFFICIENT, NORMALIZED_ZERO_EXPONENT } from "src/lib/LibDecimalFloat.sol"; import { EXPONENT_MIN, diff --git a/test/src/LibDecimalFloat.power.t.sol b/test/src/LibDecimalFloat.power.t.sol index b6054b8c..e1454277 100644 --- a/test/src/LibDecimalFloat.power.t.sol +++ b/test/src/LibDecimalFloat.power.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity =0.8.25; -import {LibDecimalFloat, COMPARE_EQUAL} from "src/lib/LibDecimalFloat.sol"; +import {LibDecimalFloat} from "src/lib/LibDecimalFloat.sol"; import {Test, console} from "forge-std/Test.sol"; diff --git a/test/src/LibDecimalFloat.power10.t.sol b/test/src/LibDecimalFloat.power10.t.sol index de692e92..10e1f2e0 100644 --- a/test/src/LibDecimalFloat.power10.t.sol +++ b/test/src/LibDecimalFloat.power10.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity =0.8.25; -import {LibDecimalFloat, COMPARE_EQUAL} from "src/lib/LibDecimalFloat.sol"; +import {LibDecimalFloat} from "src/lib/LibDecimalFloat.sol"; import {Test, console} from "forge-std/Test.sol";