diff --git a/.gas-snapshot b/.gas-snapshot index 7faa21d..b6f495f 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,120 +1,123 @@ -DecimalFloatAbsTest:testAbsDeployed(bytes32) (runs: 5096, μ: 3573478, ~: 3573418) -DecimalFloatAddTest:testAddDeployed(bytes32,bytes32) (runs: 5096, μ: 3578891, ~: 3578954) -DecimalFloatCeilTest:testCeilDeployed(bytes32) (runs: 5096, μ: 3573396, ~: 3573000) -DecimalFloatConstantsTest:testEDeployed() (gas: 3572581) -DecimalFloatConstantsTest:testMaxNegativeValueDeployed() (gas: 3572571) -DecimalFloatConstantsTest:testMaxPositiveValueDeployed() (gas: 3572572) -DecimalFloatConstantsTest:testMinNegativeValueDeployed() (gas: 3572547) -DecimalFloatConstantsTest:testMinPositiveValueDeployed() (gas: 3572570) -DecimalFloatConstantsTest:testZeroDeployed() (gas: 3572590) -DecimalFloatDivTest:testDivDeployed(bytes32,bytes32) (runs: 5096, μ: 3580693, ~: 3580610) -DecimalFloatEqTest:testEqDeployed(bytes32,bytes32) (runs: 5096, μ: 3573777, ~: 3573702) -DecimalFloatFloorTest:testFloorDeployed(bytes32) (runs: 5096, μ: 3573231, ~: 3573043) -DecimalFloatFormatTest:testFormatConstants() (gas: 3573166) -DecimalFloatFormatTest:testFormatDeployed(bytes32,bytes32,bytes32) (runs: 2568, μ: 3599609, ~: 3604266) -DecimalFloatFracTest:testFracDeployed(bytes32) (runs: 5096, μ: 3573593, ~: 3573556) -DecimalFloatFromFixedDecimalLosslessTest:testFromFixedDecimalLosslessDeployed(uint256,uint8) (runs: 5096, μ: 3574471, ~: 3574120) -DecimalFloatFromFixedDecimalLossyTest:testFromFixedDecimalLossyDeployed(uint256,uint8) (runs: 5096, μ: 3574349, ~: 3574277) -DecimalFloatGtTest:testGtDeployed(bytes32,bytes32) (runs: 5096, μ: 3573676, ~: 3573601) -DecimalFloatGteTest:testGteDeployed(bytes32,bytes32) (runs: 5096, μ: 3573748, ~: 3573674) -DecimalFloatInvTest:testInvDeployed(bytes32) (runs: 5096, μ: 3578891, ~: 3578912) -DecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5096, μ: 3572916, ~: 3572916) -DecimalFloatLtTest:testLtDeployed(bytes32,bytes32) (runs: 5096, μ: 3573653, ~: 3573578) -DecimalFloatLteTest:testLteDeployed(bytes32,bytes32) (runs: 5096, μ: 3573705, ~: 3573631) -DecimalFloatMaxTest:testMaxDeployed(bytes32,bytes32) (runs: 5096, μ: 3573751, ~: 3573689) -DecimalFloatMinTest:testMinDeployed(bytes32,bytes32) (runs: 5096, μ: 3573727, ~: 3573665) -DecimalFloatMinusTest:testMinusDeployed(bytes32) (runs: 5096, μ: 3573518, ~: 3573518) -DecimalFloatMulTest:testMulDeployed(bytes32,bytes32) (runs: 5096, μ: 3577672, ~: 3578256) -DecimalFloatPackLosslessTest:testPackDeployed(int224,int32) (runs: 5096, μ: 163826, ~: 163827) -DecimalFloatParseTest:testParseDeployed(string) (runs: 5096, μ: 3575585, ~: 3575530) -DecimalFloatPowTest:testPowDeployed(bytes32,bytes32) (runs: 5096, μ: 3622090, ~: 3602460) -DecimalFloatSqrtTest:testSqrtDeployed(bytes32) (runs: 5096, μ: 3590984, ~: 3591392) -DecimalFloatSubTest:testSubDeployed(bytes32,bytes32) (runs: 5096, μ: 3579194, ~: 3579273) -DecimalFloatToFixedDecimalLosslessTest:testToFixedDecimalLosslessDeployed(bytes32,uint8) (runs: 5096, μ: 3577132, ~: 3576770) -DecimalFloatToFixedDecimalLossyTest:testToFixedDecimalLossyDeployed(bytes32,uint8) (runs: 5096, μ: 3576661, ~: 3576354) -LibDecimalFloatAbsTest:testAbsMinValue(int32) (runs: 5042, μ: 4480, ~: 4480) -LibDecimalFloatAbsTest:testAbsNegative(int256,int32) (runs: 5096, μ: 9313, ~: 9477) -LibDecimalFloatAbsTest:testAbsNonNegative(int256,int32) (runs: 5096, μ: 8579, ~: 8306) -LibDecimalFloatCeilTest:testCeilExamples() (gas: 34682) -LibDecimalFloatCeilTest:testCeilInRange(int224,int256) (runs: 5096, μ: 10768, ~: 10395) -LibDecimalFloatCeilTest:testCeilLessThanMin(int224,int256) (runs: 5096, μ: 9721, ~: 9481) -LibDecimalFloatCeilTest:testCeilNonNegative(int224,int256) (runs: 5096, μ: 8643, ~: 8889) -LibDecimalFloatCeilTest:testCeilNotReverts(bytes32) (runs: 5096, μ: 607, ~: 408) +DecimalFloatAbsTest:testAbsDeployed(bytes32) (runs: 5096, μ: 3630849, ~: 3630783) +DecimalFloatAddTest:testAddDeployed(bytes32,bytes32) (runs: 5096, μ: 3635891, ~: 3636279) +DecimalFloatCeilTest:testCeilDeployed(bytes32) (runs: 5096, μ: 3630808, ~: 3630365) +DecimalFloatConstantsTest:testEDeployed() (gas: 3629946) +DecimalFloatConstantsTest:testMaxNegativeValueDeployed() (gas: 3629936) +DecimalFloatConstantsTest:testMaxPositiveValueDeployed() (gas: 3629937) +DecimalFloatConstantsTest:testMinNegativeValueDeployed() (gas: 3629912) +DecimalFloatConstantsTest:testMinPositiveValueDeployed() (gas: 3629935) +DecimalFloatConstantsTest:testZeroDeployed() (gas: 3629955) +DecimalFloatDivTest:testDivDeployed(bytes32,bytes32) (runs: 5096, μ: 3637817, ~: 3638031) +DecimalFloatEqTest:testEqDeployed(bytes32,bytes32) (runs: 5096, μ: 3631168, ~: 3631067) +DecimalFloatFloorTest:testFloorDeployed(bytes32) (runs: 5096, μ: 3630905, ~: 3630408) +DecimalFloatFormatTest:testFormatConstants() (gas: 3630531) +DecimalFloatFormatTest:testFormatDeployed(bytes32,bytes32,bytes32) (runs: 5096, μ: 3655597, ~: 3662378) +DecimalFloatFracTest:testFracDeployed(bytes32) (runs: 5096, μ: 3630962, ~: 3630921) +DecimalFloatFromFixedDecimalLosslessTest:testFromFixedDecimalLosslessDeployed(uint256,uint8) (runs: 5096, μ: 3631819, ~: 3631485) +DecimalFloatFromFixedDecimalLossyTest:testFromFixedDecimalLossyDeployed(uint256,uint8) (runs: 5096, μ: 3631710, ~: 3631642) +DecimalFloatGtTest:testGtDeployed(bytes32,bytes32) (runs: 5096, μ: 3631067, ~: 3630966) +DecimalFloatGteTest:testGteDeployed(bytes32,bytes32) (runs: 5096, μ: 3631141, ~: 3631039) +DecimalFloatInvTest:testInvDeployed(bytes32) (runs: 5096, μ: 3636151, ~: 3636277) +DecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5096, μ: 3630281, ~: 3630281) +DecimalFloatLtTest:testLtDeployed(bytes32,bytes32) (runs: 5096, μ: 3631044, ~: 3630943) +DecimalFloatLteTest:testLteDeployed(bytes32,bytes32) (runs: 5096, μ: 3631098, ~: 3630996) +DecimalFloatMaxTest:testMaxDeployed(bytes32,bytes32) (runs: 5096, μ: 3631142, ~: 3631054) +DecimalFloatMinTest:testMinDeployed(bytes32,bytes32) (runs: 5096, μ: 3631118, ~: 3631030) +DecimalFloatMinusTest:testMinusDeployed(bytes32) (runs: 5096, μ: 3630880, ~: 3630883) +DecimalFloatMulTest:testMulDeployed(bytes32,bytes32) (runs: 5096, μ: 3635218, ~: 3635682) +DecimalFloatPackLosslessTest:testPackDeployed(int224,int32) (runs: 5096, μ: 163825, ~: 163827) +DecimalFloatParseTest:testParseDeployed(string) (runs: 5096, μ: 3633842, ~: 3632921) +DecimalFloatPowTest:testPowDeployed(bytes32,bytes32) (runs: 5096, μ: 3663059, ~: 3635707) +DecimalFloatSqrtTest:testSqrtDeployed(bytes32) (runs: 5096, μ: 3648127, ~: 3648881) +DecimalFloatSubTest:testSubDeployed(bytes32,bytes32) (runs: 5096, μ: 3636212, ~: 3636620) +DecimalFloatToFixedDecimalLosslessTest:testToFixedDecimalLosslessDeployed(bytes32,uint8) (runs: 5096, μ: 3634281, ~: 3634135) +DecimalFloatToFixedDecimalLossyTest:testToFixedDecimalLossyDeployed(bytes32,uint8) (runs: 5096, μ: 3633780, ~: 3633719) +LibDecimalFloatAbsTest:testAbsMinValue(int32) (runs: 5096, μ: 4480, ~: 4480) +LibDecimalFloatAbsTest:testAbsNegative(int256,int32) (runs: 5096, μ: 2731, ~: 2998) +LibDecimalFloatAbsTest:testAbsNonNegative(int256,int32) (runs: 5096, μ: 2256, ~: 2543) +LibDecimalFloatCeilTest:testCeilExamples() (gas: 49683) +LibDecimalFloatCeilTest:testCeilInRange(int224,int256) (runs: 5096, μ: 4525, ~: 4530) +LibDecimalFloatCeilTest:testCeilLessThanMin(int224,int256) (runs: 5096, μ: 3528, ~: 3839) +LibDecimalFloatCeilTest:testCeilNonNegative(int224,int256) (runs: 5096, μ: 2316, ~: 2440) +LibDecimalFloatCeilTest:testCeilNotReverts(bytes32) (runs: 5096, μ: 634, ~: 408) LibDecimalFloatCeilTest:testCeilZero(int32) (runs: 5096, μ: 1915, ~: 1915) LibDecimalFloatConstantsTest:testFloatE() (gas: 534) LibDecimalFloatConstantsTest:testFloatHalf() (gas: 513) LibDecimalFloatConstantsTest:testFloatMaxNegativeValue() (gas: 556) -LibDecimalFloatConstantsTest:testFloatMaxNegativeValueIsMax(bytes32) (runs: 5077, μ: 4165, ~: 4281) +LibDecimalFloatConstantsTest:testFloatMaxNegativeValueIsMax(bytes32) (runs: 5096, μ: 4149, ~: 4281) LibDecimalFloatConstantsTest:testFloatMaxPositiveValue() (gas: 512) -LibDecimalFloatConstantsTest:testFloatMaxPositiveValueIsMax(bytes32) (runs: 5096, μ: 707, ~: 748) +LibDecimalFloatConstantsTest:testFloatMaxPositiveValueIsMax(bytes32) (runs: 5096, μ: 698, ~: 748) LibDecimalFloatConstantsTest:testFloatMinNegativeValue() (gas: 512) -LibDecimalFloatConstantsTest:testFloatMinNegativeValueIsMin(bytes32) (runs: 5096, μ: 661, ~: 622) +LibDecimalFloatConstantsTest:testFloatMinNegativeValueIsMin(bytes32) (runs: 5096, μ: 665, ~: 622) LibDecimalFloatConstantsTest:testFloatMinPositiveValue() (gas: 534) -LibDecimalFloatConstantsTest:testFloatMinPositiveValueIsMin(bytes32) (runs: 5073, μ: 4628, ~: 4559) +LibDecimalFloatConstantsTest:testFloatMinPositiveValueIsMin(bytes32) (runs: 5096, μ: 4638, ~: 4559) LibDecimalFloatConstantsTest:testFloatOne() (gas: 535) LibDecimalFloatConstantsTest:testFloatTwo() (gas: 557) LibDecimalFloatConstantsTest:testFloatZero() (gas: 482) -LibDecimalFloatDecimalAddTest:testAddPacked(bytes32,bytes32) (runs: 5096, μ: 7996, ~: 8125) -LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessFail(uint256,uint8) (runs: 4553, μ: 9247, ~: 9292) -LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessMem(uint256,uint8) (runs: 5096, μ: 4854, ~: 4779) -LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessPass(uint256,uint8) (runs: 5096, μ: 4259, ~: 4233) +LibDecimalFloatDecimalAddTest:testAddPacked(bytes32,bytes32) (runs: 5096, μ: 7607, ~: 7997) +LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessFail(uint256,uint8) (runs: 5096, μ: 6144, ~: 6184) +LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessMem(uint256,uint8) (runs: 5096, μ: 1735, ~: 1665) +LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessPass(uint256,uint8) (runs: 5096, μ: 1142, ~: 1122) LibDecimalFloatDecimalLosslessTest:testToFixedDecimalLosslessFail() (gas: 4640) -LibDecimalFloatDecimalLosslessTest:testToFixedDecimalLosslessPacked(bytes32,uint8) (runs: 5096, μ: 6137, ~: 5892) -LibDecimalFloatDecimalLosslessTest:testToFixedDecimalLosslessPass(int256,int256,uint8) (runs: 5096, μ: 13679, ~: 13644) -LibDecimalFloatDecimalTest:testFixedDecimalRoundTripLossless(uint256,uint8) (runs: 5096, μ: 4513, ~: 4440) +LibDecimalFloatDecimalLosslessTest:testToFixedDecimalLosslessPacked(bytes32,uint8) (runs: 5096, μ: 5925, ~: 5892) +LibDecimalFloatDecimalLosslessTest:testToFixedDecimalLosslessPass(int256,int256,uint8) (runs: 5096, μ: 5354, ~: 5232) +LibDecimalFloatDecimalTest:testFixedDecimalRoundTripLossless(uint256,uint8) (runs: 5096, μ: 1403, ~: 1337) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyComplicated() (gas: 184877) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyMax() (gas: 172382) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOne() (gas: 184921) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOneMillion() (gas: 184856) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOverflow() (gas: 213925) -LibDecimalFloatDecimalTest:testFromFixedDecimalLossyPacked(uint256,uint8) (runs: 5096, μ: 4939, ~: 4859) -LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateOne(uint256,uint8) (runs: 5096, μ: 1492, ~: 1454) -LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateZero(uint256,uint8) (runs: 5096, μ: 1567, ~: 1377) -LibDecimalFloatDecimalTest:testToFixedDecimalLosslessScaleUp(int256,int256,uint8) (runs: 2612, μ: 13867, ~: 13877) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyExponentOverflow(int256,int256,uint8) (runs: 5096, μ: 13559, ~: 13333) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyIdentity(int256,uint8) (runs: 5096, μ: 8392, ~: 8170) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyNegative(int256,int256,uint8) (runs: 5096, μ: 10033, ~: 10233) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyPacked(bytes32,uint8) (runs: 5096, μ: 5574, ~: 5432) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyScaleUpOverflow(int256,int256,uint8) (runs: 2483, μ: 14262, ~: 14480) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncate(int256,int256,uint8) (runs: 5096, μ: 12369, ~: 12156) +LibDecimalFloatDecimalTest:testFromFixedDecimalLossyPacked(uint256,uint8) (runs: 5096, μ: 1829, ~: 1756) +LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateOne(uint256,uint8) (runs: 5096, μ: 1483, ~: 1454) +LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateZero(uint256,uint8) (runs: 5096, μ: 1536, ~: 1377) +LibDecimalFloatDecimalTest:testToFixedDecimalLosslessScaleUp(int256,int256,uint8) (runs: 5096, μ: 7765, ~: 7642) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyExponentOverflow(int256,int256,uint8) (runs: 5096, μ: 7703, ~: 7655) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyIdentity(int256,uint8) (runs: 5096, μ: 2102, ~: 2474) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyNegative(int256,int256,uint8) (runs: 5096, μ: 5963, ~: 6150) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyPacked(bytes32,uint8) (runs: 5096, μ: 5262, ~: 5432) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyScaleUpOverflow(int256,int256,uint8) (runs: 5096, μ: 8982, ~: 9163) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncate(int256,int256,uint8) (runs: 5096, μ: 4639, ~: 4421) LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncateLossless() (gas: 4135) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyUnderflow(int256,int256,uint8) (runs: 5096, μ: 11418, ~: 11348) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyUnderflow(int256,int256,uint8) (runs: 5096, μ: 3601, ~: 3527) LibDecimalFloatDecimalTest:testToFixedDecimalLossyZero(int256,uint8) (runs: 5096, μ: 748, ~: 748) -LibDecimalFloatDivTest:testDivByNegativeOneFloat(int224,int32) (runs: 5096, μ: 338189, ~: 334483) -LibDecimalFloatDivTest:testDivByOneFloat(int224,int32) (runs: 5096, μ: 314679, ~: 312621) -LibDecimalFloatDivTest:testDivPacked(bytes32,bytes32) (runs: 5096, μ: 9729, ~: 9661) -LibDecimalFloatEqTest:testEqPacked(bytes32,bytes32) (runs: 5096, μ: 2678, ~: 2605) -LibDecimalFloatEqTest:testEqXNotYExponents(bytes32,bytes32) (runs: 5096, μ: 1490, ~: 1384) +LibDecimalFloatDeployTest:testDecimalFloatZoltu() (gas: 7272663) +LibDecimalFloatDeployTest:testDecimalFloatZoltuProd() (gas: 16002) +LibDecimalFloatDivTest:testDivByNegativeOneFloat(int224,int32) (runs: 5096, μ: 338250, ~: 341377) +LibDecimalFloatDivTest:testDivByOneFloat(int224,int32) (runs: 5096, μ: 311642, ~: 313702) +LibDecimalFloatDivTest:testDivPacked(bytes32,bytes32) (runs: 5096, μ: 9490, ~: 9709) +LibDecimalFloatEqTest:testEqPacked(bytes32,bytes32) (runs: 5096, μ: 2706, ~: 2605) +LibDecimalFloatEqTest:testEqXNotYExponents(bytes32,bytes32) (runs: 5096, μ: 1531, ~: 1384) LibDecimalFloatEqTest:testEqZero(int32) (runs: 5096, μ: 1603, ~: 1603) -LibDecimalFloatFloorTest:testFloorExamples() (gas: 21113) -LibDecimalFloatFloorTest:testFloorGas0() (gas: 989) -LibDecimalFloatFloorTest:testFloorGasTiny() (gas: 887) +LibDecimalFloatFloorTest:testFloorExamples() (gas: 53915) +LibDecimalFloatFloorTest:testFloorGas0() (gas: 1056) +LibDecimalFloatFloorTest:testFloorGasTiny() (gas: 888) LibDecimalFloatFloorTest:testFloorGasZero() (gas: 539) -LibDecimalFloatFloorTest:testFloorInRange(int224,int256) (runs: 5096, μ: 10074, ~: 10101) -LibDecimalFloatFloorTest:testFloorLessThanMin(int224,int256) (runs: 5096, μ: 9281, ~: 9292) -LibDecimalFloatFloorTest:testFloorNonNegative(int224,int256) (runs: 5096, μ: 8583, ~: 8837) -LibDecimalFloatFloorTest:testFloorNotReverts(bytes32) (runs: 5096, μ: 459, ~: 362) +LibDecimalFloatFloorTest:testFloorInRangeNegative(int224,int256) (runs: 5096, μ: 12351, ~: 12658) +LibDecimalFloatFloorTest:testFloorInRangeNonNegative(int224,int256) (runs: 5096, μ: 4610, ~: 4481) +LibDecimalFloatFloorTest:testFloorLessThanMin(int224,int256) (runs: 5096, μ: 3112, ~: 2992) +LibDecimalFloatFloorTest:testFloorNonNegative(int224,int256) (runs: 5096, μ: 2265, ~: 2395) +LibDecimalFloatFloorTest:testFloorNotReverts(bytes32) (runs: 5096, μ: 630, ~: 362) LibDecimalFloatFracTest:testFracExamples() (gas: 36585) LibDecimalFloatFracTest:testFracGas0() (gas: 990) LibDecimalFloatFracTest:testFracGasTiny() (gas: 875) LibDecimalFloatFracTest:testFracGasZero() (gas: 794) -LibDecimalFloatFracTest:testFracInRange(int224,int256) (runs: 5096, μ: 9896, ~: 9907) -LibDecimalFloatFracTest:testFracLessThanMin(int224,int256) (runs: 5096, μ: 9318, ~: 9331) -LibDecimalFloatFracTest:testFracNonNegative(int224,int256) (runs: 5096, μ: 8816, ~: 9064) -LibDecimalFloatFracTest:testFracNotReverts(bytes32) (runs: 5096, μ: 627, ~: 606) +LibDecimalFloatFracTest:testFracInRange(int224,int256) (runs: 5096, μ: 3416, ~: 3465) +LibDecimalFloatFracTest:testFracLessThanMin(int224,int256) (runs: 5096, μ: 2847, ~: 2889) +LibDecimalFloatFracTest:testFracNonNegative(int224,int256) (runs: 5096, μ: 2491, ~: 2622) +LibDecimalFloatFracTest:testFracNotReverts(bytes32) (runs: 5096, μ: 628, ~: 606) LibDecimalFloatGtTest:testGtGasAZero() (gas: 978) LibDecimalFloatGtTest:testGtGasBZero() (gas: 978) LibDecimalFloatGtTest:testGtGasBothZero() (gas: 736) LibDecimalFloatGtTest:testGtGasDifferentSigns() (gas: 1011) LibDecimalFloatGtTest:testGtGasExponentDiffOverflow() (gas: 1179) LibDecimalFloatGtTest:testGtOneEAny(bytes32) (runs: 5096, μ: 658, ~: 658) -LibDecimalFloatGtTest:testGtReference(int224,int32,int224,int32) (runs: 5096, μ: 5304, ~: 3715) +LibDecimalFloatGtTest:testGtReference(int224,int32,int224,int32) (runs: 5096, μ: 8013, ~: 8950) LibDecimalFloatGtTest:testGtX(int224,int32) (runs: 5096, μ: 1066, ~: 1067) -LibDecimalFloatGtTest:testGtXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 9507, ~: 9231) -LibDecimalFloatGtTest:testGtXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 9966, ~: 10116) -LibDecimalFloatGtTest:testGtXNotY(bytes32,bytes32) (runs: 5096, μ: 1491, ~: 1383) -LibDecimalFloatGtTest:testGtXPositiveYNegative(int256,int32,int256,int32) (runs: 5096, μ: 12139, ~: 12031) -LibDecimalFloatGtTest:testGtXPositiveYZero(int256,int32,int32) (runs: 5096, μ: 9169, ~: 8907) +LibDecimalFloatGtTest:testGtXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 3226, ~: 3465) +LibDecimalFloatGtTest:testGtXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 3396, ~: 3649) +LibDecimalFloatGtTest:testGtXNotY(bytes32,bytes32) (runs: 5096, μ: 1530, ~: 1383) +LibDecimalFloatGtTest:testGtXPositiveYNegative(int256,int32,int256,int32) (runs: 5096, μ: 4274, ~: 4276) +LibDecimalFloatGtTest:testGtXPositiveYZero(int256,int32,int32) (runs: 5096, μ: 2876, ~: 3141) LibDecimalFloatGtTest:testGtZero(int32,int32) (runs: 5096, μ: 1609, ~: 1609) LibDecimalFloatGteTest:testGteGasAZero() (gas: 981) LibDecimalFloatGteTest:testGteGasBZero() (gas: 1025) @@ -122,87 +125,88 @@ LibDecimalFloatGteTest:testGteGasBothZero() (gas: 738) LibDecimalFloatGteTest:testGteGasDifferentSigns() (gas: 1033) LibDecimalFloatGteTest:testGteGasExponentDiffOverflow() (gas: 1138) LibDecimalFloatGteTest:testGteOneEAny(bytes32) (runs: 5096, μ: 658, ~: 658) -LibDecimalFloatGteTest:testGteReference(int224,int32,int224,int32) (runs: 5096, μ: 5348, ~: 3760) +LibDecimalFloatGteTest:testGteReference(int224,int32,int224,int32) (runs: 5096, μ: 8072, ~: 9070) LibDecimalFloatGteTest:testGteX(int224,int32) (runs: 5096, μ: 1109, ~: 1110) -LibDecimalFloatGteTest:testGteXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 9539, ~: 9263) -LibDecimalFloatGteTest:testGteXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 9979, ~: 10128) -LibDecimalFloatGteTest:testGteXNotLtY(bytes32,bytes32) (runs: 5096, μ: 1103, ~: 1028) -LibDecimalFloatGteTest:testGteXPositiveYNegative(int256,int32,int256,int32) (runs: 5096, μ: 12167, ~: 12059) -LibDecimalFloatGteTest:testGteXPositiveYZero(int256,int32,int32) (runs: 5096, μ: 8775, ~: 8506) +LibDecimalFloatGteTest:testGteXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 3256, ~: 3497) +LibDecimalFloatGteTest:testGteXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 3409, ~: 3661) +LibDecimalFloatGteTest:testGteXNotLtY(bytes32,bytes32) (runs: 5096, μ: 1129, ~: 1028) +LibDecimalFloatGteTest:testGteXPositiveYNegative(int256,int32,int256,int32) (runs: 5096, μ: 4300, ~: 4304) +LibDecimalFloatGteTest:testGteXPositiveYZero(int256,int32,int32) (runs: 5096, μ: 2480, ~: 2755) LibDecimalFloatGteTest:testGteZero(int32,int32) (runs: 5096, μ: 1654, ~: 1654) LibDecimalFloatImplementationAddTest:testAdd123456789987654321() (gas: 2134) LibDecimalFloatImplementationAddTest:testAdd123456789e9987654321() (gas: 2185) -LibDecimalFloatImplementationAddTest:testAddNeverRevert(int256,int256,int256,int256) (runs: 5096, μ: 12911, ~: 12936) +LibDecimalFloatImplementationAddTest:testAddNeverRevert(int256,int256,int256,int256) (runs: 5096, μ: 5075, ~: 5124) LibDecimalFloatImplementationAddTest:testAddOneOneNotMaximized() (gas: 3113) LibDecimalFloatImplementationAddTest:testAddOneOnePreMaximized() (gas: 1305) LibDecimalFloatImplementationAddTest:testAddOneZero() (gas: 463) LibDecimalFloatImplementationAddTest:testAddRevertMaxA() (gas: 6056) -LibDecimalFloatImplementationAddTest:testAddSameExponent(int256,int256) (runs: 4314, μ: 6327, ~: 6453) +LibDecimalFloatImplementationAddTest:testAddSameExponent(int256,int256) (runs: 5096, μ: 6360, ~: 6453) LibDecimalFloatImplementationAddTest:testAddZero() (gas: 483) -LibDecimalFloatImplementationAddTest:testAddZeroAnyExponent(int128) (runs: 5096, μ: 8213, ~: 8248) +LibDecimalFloatImplementationAddTest:testAddZeroAnyExponent(int128) (runs: 5096, μ: 1736, ~: 1668) LibDecimalFloatImplementationAddTest:testAddZeroOne() (gas: 483) -LibDecimalFloatImplementationAddTest:testAddZeroToAnyNonZero(int256,int256,int256) (runs: 5046, μ: 11901, ~: 11856) +LibDecimalFloatImplementationAddTest:testAddZeroToAnyNonZero(int256,int256,int256) (runs: 5096, μ: 6555, ~: 6480) LibDecimalFloatImplementationAddTest:testAddingSmallToLargeReturnsLargeExamples() (gas: 62746) -LibDecimalFloatImplementationAddTest:testAddingSmallToLargeReturnsLargeFuzz(int256,int256,int256,int256) (runs: 2446, μ: 16744, ~: 16846) +LibDecimalFloatImplementationAddTest:testAddingSmallToLargeReturnsLargeFuzz(int256,int256,int256,int256) (runs: 5096, μ: 11428, ~: 11535) LibDecimalFloatImplementationAddTest:testGasAddOne() (gas: 1845) LibDecimalFloatImplementationAddTest:testGasAddZero() (gas: 377) -LibDecimalFloatImplementationAddTest:testOverflowChecks(int256,int256) (runs: 5096, μ: 704, ~: 691) -LibDecimalFloatImplementationCharacteristicMantissaTest:testCharacteristicMantissaExamples() (gas: 7919) -LibDecimalFloatImplementationCharacteristicMantissaTest:testCharacteristicMantissaNegExponentLarge(int256,int256) (runs: 5096, μ: 8665, ~: 8846) -LibDecimalFloatImplementationCharacteristicMantissaTest:testCharacteristicMantissaNegExponentSmall(int256) (runs: 5096, μ: 100696, ~: 100696) -LibDecimalFloatImplementationCharacteristicMantissaTest:testCharacteristicMantissaNonNegExponent(int256,int256) (runs: 5096, μ: 8135, ~: 7912) -LibDecimalFloatImplementationDivTest:testDiv1Over3() (gas: 3829) -LibDecimalFloatImplementationDivTest:testDiv1Over3Gas0() (gas: 2536) -LibDecimalFloatImplementationDivTest:testDiv1Over3Gas10() (gas: 20933) -LibDecimalFloatImplementationDivTest:testDiv1Over9Over1Over3() (gas: 10756) -LibDecimalFloatImplementationDivTest:testDiv1e18Over3() (gas: 3383) -LibDecimalFloatImplementationDivTest:testDivBy1(int256,int256) (runs: 5096, μ: 264291, ~: 268985) -LibDecimalFloatImplementationDivTest:testDivByNegativeOneFloat(int256,int256) (runs: 5096, μ: 268411, ~: 275358) -LibDecimalFloatImplementationDivTest:testDivMaxPositiveValueDenominatorNotRevert(int256,int256) (runs: 5096, μ: 2576, ~: 2616) -LibDecimalFloatImplementationDivTest:testDivNegative1Over3() (gas: 3978) -LibDecimalFloatImplementationDivTest:testDivOOMs5and2() (gas: 2828) -LibDecimalFloatImplementationDivTest:testDivOOMsOverTen() (gas: 3765) -LibDecimalFloatImplementationDivTest:testDivTenOverOOMs() (gas: 3724) -LibDecimalFloatImplementationDivTest:testDivZero(int256,int256) (runs: 5096, μ: 9286, ~: 9247) -LibDecimalFloatImplementationDivTest:testUnnormalizedThreesDiv0(int256,int256) (runs: 100, μ: 22007748, ~: 21926298) +LibDecimalFloatImplementationAddTest:testOverflowChecks(int256,int256) (runs: 5096, μ: 711, ~: 710) +LibDecimalFloatImplementationDivTest:testDiv1Over3() (gas: 3805) +LibDecimalFloatImplementationDivTest:testDiv1Over3Gas0() (gas: 2512) +LibDecimalFloatImplementationDivTest:testDiv1Over3Gas10() (gas: 20913) +LibDecimalFloatImplementationDivTest:testDiv1Over9Over1Over3() (gas: 10748) +LibDecimalFloatImplementationDivTest:testDiv1e18Over3() (gas: 3381) +LibDecimalFloatImplementationDivTest:testDivBy1(int256,int256) (runs: 5096, μ: 259617, ~: 263258) +LibDecimalFloatImplementationDivTest:testDivByNegativeOneFloat(int256,int256) (runs: 5096, μ: 261986, ~: 269370) +LibDecimalFloatImplementationDivTest:testDivMaxPositiveValueDenominatorNotRevert(int256,int256) (runs: 5096, μ: 2587, ~: 2646) +LibDecimalFloatImplementationDivTest:testDivMinPositiveValueDenominatorRevert(int256,int256) (runs: 5096, μ: 6863, ~: 6912) +LibDecimalFloatImplementationDivTest:testDivNegative1Over3() (gas: 3954) +LibDecimalFloatImplementationDivTest:testDivOOMs5and2() (gas: 2826) +LibDecimalFloatImplementationDivTest:testDivOOMsOverTen() (gas: 3829) +LibDecimalFloatImplementationDivTest:testDivTenOverOOMs() (gas: 3722) +LibDecimalFloatImplementationDivTest:testDivZero(int256,int256) (runs: 5096, μ: 5366, ~: 5429) +LibDecimalFloatImplementationDivTest:testUnnormalizedThreesDiv0(int256,int256) (runs: 100, μ: 22006847, ~: 21962709) LibDecimalFloatImplementationEqTest:testEqGasAZero() (gas: 425) LibDecimalFloatImplementationEqTest:testEqGasBZero() (gas: 468) LibDecimalFloatImplementationEqTest:testEqGasBothZero() (gas: 445) LibDecimalFloatImplementationEqTest:testEqGasDifferentSigns() (gas: 477) LibDecimalFloatImplementationEqTest:testEqGasExponentDiffOverflow() (gas: 527) -LibDecimalFloatImplementationEqTest:testEqNotReverts(int256,int256,int256,int256) (runs: 5096, μ: 646, ~: 671) +LibDecimalFloatImplementationEqTest:testEqNotReverts(int256,int256,int256,int256) (runs: 5096, μ: 626, ~: 569) LibDecimalFloatImplementationEqTest:testEqOneEAny(int256,int256) (runs: 5096, μ: 580, ~: 580) -LibDecimalFloatImplementationEqTest:testEqReference(int256,int256,int256,int256) (runs: 5096, μ: 7034, ~: 8575) +LibDecimalFloatImplementationEqTest:testEqReference(int256,int256,int256,int256) (runs: 5096, μ: 6566, ~: 7383) LibDecimalFloatImplementationEqTest:testEqX(int256) (runs: 5096, μ: 554, ~: 554) -LibDecimalFloatImplementationEqTest:testEqXEAnyVsXEAny(int256,int256,int256) (runs: 5048, μ: 4025, ~: 4022) -LibDecimalFloatImplementationEqTest:testEqXEqY(int256,int256,int256,int256) (runs: 5096, μ: 719, ~: 744) -LibDecimalFloatImplementationEqTest:testEqXNotY(int256,int256,int256,int256) (runs: 5096, μ: 3596, ~: 3621) +LibDecimalFloatImplementationEqTest:testEqXEAnyVsXEAny(int256,int256,int256) (runs: 5096, μ: 4030, ~: 4022) +LibDecimalFloatImplementationEqTest:testEqXEqY(int256,int256,int256,int256) (runs: 5096, μ: 699, ~: 642) +LibDecimalFloatImplementationEqTest:testEqXNotY(int256,int256,int256,int256) (runs: 5096, μ: 5181, ~: 5251) LibDecimalFloatImplementationEqTest:testEqZero(int256,int256) (runs: 5096, μ: 602, ~: 602) +LibDecimalFloatImplementationIntFracTest:testIntFracExamples() (gas: 7940) +LibDecimalFloatImplementationIntFracTest:testIntFracNegExponentLarge(int256,int256) (runs: 5096, μ: 2148, ~: 2392) +LibDecimalFloatImplementationIntFracTest:testIntFracNegExponentSmall(int256) (runs: 5096, μ: 100629, ~: 100629) +LibDecimalFloatImplementationIntFracTest:testIntFracNonNegExponent(int256,int256) (runs: 5096, μ: 1804, ~: 1780) LibDecimalFloatImplementationInvTest:testInv0() (gas: 4204) -LibDecimalFloatImplementationInvTest:testInvGas0() (gas: 2217) -LibDecimalFloatImplementationInvTest:testInvReference(int256,int256) (runs: 5046, μ: 13526, ~: 13598) -LibDecimalFloatImplementationInvTest:testInvSlowGas0() (gas: 2529) +LibDecimalFloatImplementationInvTest:testInvGas0() (gas: 2215) +LibDecimalFloatImplementationInvTest:testInvReference(int256,int256) (runs: 5096, μ: 9620, ~: 9701) +LibDecimalFloatImplementationInvTest:testInvSlowGas0() (gas: 2527) LibDecimalFloatImplementationLog10Test:testExactLogs() (gas: 1229922) LibDecimalFloatImplementationLog10Test:testExactLookupsLog10() (gas: 1273910) LibDecimalFloatImplementationLog10Test:testInterpolatedLookups() (gas: 1229175) LibDecimalFloatImplementationLog10Test:testLog10One() (gas: 1402769) LibDecimalFloatImplementationLog10Test:testSub1() (gas: 1230040) LibDecimalFloatImplementationLookupLogTableValTest:testLookupLogTableVal() (gas: 1312355) -LibDecimalFloatImplementationMaximizeTest:testMaximizedEverything(int256,int256) (runs: 5096, μ: 9042, ~: 9077) +LibDecimalFloatImplementationMaximizeTest:testMaximizedEverything(int256,int256) (runs: 5096, μ: 2628, ~: 2672) LibDecimalFloatImplementationMaximizeTest:testMaximizedExamples() (gas: 130254) -LibDecimalFloatImplementationMaximizeTest:testMaximizedIdempotent(int256,int256) (runs: 5096, μ: 9240, ~: 9270) -LibDecimalFloatImplementationMaximizeTest:testMaximizedReference(int256,int256) (runs: 5096, μ: 12525, ~: 13353) -LibDecimalFloatImplementationMinusTest:testMinusIsSubZero(int256,int256,int256) (runs: 5096, μ: 11439, ~: 11413) +LibDecimalFloatImplementationMaximizeTest:testMaximizedIdempotent(int256,int256) (runs: 5096, μ: 2830, ~: 2870) +LibDecimalFloatImplementationMaximizeTest:testMaximizedReference(int256,int256) (runs: 5096, μ: 6025, ~: 6636) +LibDecimalFloatImplementationMinusTest:testMinusIsSubZero(int256,int256,int256) (runs: 5096, μ: 3598, ~: 3531) LibDecimalFloatImplementationMulTest:testMul123456789987654321() (gas: 1718) -LibDecimalFloatImplementationMulTest:testMul123456789987654321WithExponents(int128,int128) (runs: 5096, μ: 13056, ~: 13149) -LibDecimalFloatImplementationMulTest:testMul1_3979_0_5() (gas: 2512) +LibDecimalFloatImplementationMulTest:testMul123456789987654321WithExponents(int128,int128) (runs: 5096, μ: 4980, ~: 5201) +LibDecimalFloatImplementationMulTest:testMul1_3979_0_5() (gas: 2510) LibDecimalFloatImplementationMulTest:testMul1e181e19() (gas: 1765) LibDecimalFloatImplementationMulTest:testMulGasOne() (gas: 1450) LibDecimalFloatImplementationMulTest:testMulGasZero() (gas: 318) -LibDecimalFloatImplementationMulTest:testMulMaxSignedCoefficient() (gas: 2832) +LibDecimalFloatImplementationMulTest:testMulMaxSignedCoefficient() (gas: 2830) LibDecimalFloatImplementationMulTest:testMulNegativeOne() (gas: 1817) LibDecimalFloatImplementationMulTest:testMulNegativeOneOne() (gas: 1873) -LibDecimalFloatImplementationMulTest:testMulNotRevertAnyExpectation(int256,int256,int256,int256) (runs: 5096, μ: 13809, ~: 13105) +LibDecimalFloatImplementationMulTest:testMulNotRevertAnyExpectation(int256,int256,int256,int256) (runs: 5096, μ: 6043, ~: 5223) LibDecimalFloatImplementationMulTest:testMulOneNegativeOne() (gas: 1849) LibDecimalFloatImplementationMulTest:testMulOneOne() (gas: 1741) LibDecimalFloatImplementationMulTest:testMulOneZero() (gas: 655) @@ -212,52 +216,52 @@ LibDecimalFloatImplementationMulTest:testMulZeroOne() (gas: 612) LibDecimalFloatImplementationPow10Test:testExactLookupsPow10() (gas: 1243871) LibDecimalFloatImplementationPow10Test:testExactPows() (gas: 1224263) LibDecimalFloatImplementationPow10Test:testInterpolatedLookupsPower() (gas: 1258298) -LibDecimalFloatImplementationPow10Test:testNoRevert(int224,int32) (runs: 3560, μ: 1230372, ~: 1228383) +LibDecimalFloatImplementationPow10Test:testNoRevert(int224,int32) (runs: 5096, μ: 1223642, ~: 1223730) LibDecimalFloatImplementationPow10Test:testPow10One() (gas: 1434006) -LibDecimalFloatImplementationSubTest:testSubIsAdd(int256,int256,int256,int256) (runs: 5080, μ: 15611, ~: 15807) -LibDecimalFloatImplementationSubTest:testSubMinSignedValue(int256,int256,int256) (runs: 5096, μ: 14427, ~: 14472) +LibDecimalFloatImplementationSubTest:testSubIsAdd(int256,int256,int256,int256) (runs: 5096, μ: 10280, ~: 10441) +LibDecimalFloatImplementationSubTest:testSubMinSignedValue(int256,int256,int256) (runs: 5096, μ: 6585, ~: 6681) LibDecimalFloatImplementationSubTest:testSubOneFromMax() (gas: 3331) -LibDecimalFloatImplementationSubTest:testSubSelf(int224,int32) (runs: 5096, μ: 2951, ~: 3109) -LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyMixedAB(uint256,uint256,uint256,int256) (runs: 5096, μ: 5922, ~: 5849) -LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyMixedABOverflow(uint256,uint256,uint256,int256) (runs: 5073, μ: 9894, ~: 9885) -LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyMixedBA(uint256,uint256,uint256,int256) (runs: 5073, μ: 9893, ~: 9883) -LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyMixedBAOverflow(uint256,uint256,int256) (runs: 5096, μ: 5158, ~: 5104) -LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyNegative(uint256,uint256,uint256,int256) (runs: 5096, μ: 5875, ~: 5798) -LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyNegativeOverflow(uint256,uint256,uint256,int256) (runs: 5073, μ: 9760, ~: 9748) -LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyPositive(uint256,uint256,uint256,int256) (runs: 5096, μ: 5620, ~: 5550) -LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyPositiveOverflow(uint256,uint256,uint256,int256) (runs: 5073, μ: 9651, ~: 9646) +LibDecimalFloatImplementationSubTest:testSubSelf(int224,int32) (runs: 5096, μ: 2931, ~: 3037) +LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyMixedAB(uint256,uint256,uint256,int256) (runs: 5096, μ: 1609, ~: 1545) +LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyMixedABOverflow(uint256,uint256,uint256,int256) (runs: 5096, μ: 5583, ~: 5582) +LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyMixedBA(uint256,uint256,uint256,int256) (runs: 5096, μ: 5581, ~: 5580) +LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyMixedBAOverflow(uint256,uint256,int256) (runs: 5096, μ: 1449, ~: 1400) +LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyNegative(uint256,uint256,uint256,int256) (runs: 5096, μ: 1562, ~: 1494) +LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyNegativeOverflow(uint256,uint256,uint256,int256) (runs: 5096, μ: 5448, ~: 5445) +LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyPositive(uint256,uint256,uint256,int256) (runs: 5096, μ: 1305, ~: 1243) +LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest:testUnabsUnsignedMulOrDivLossyPositiveOverflow(uint256,uint256,uint256,int256) (runs: 5096, μ: 5340, ~: 5343) LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentExamples() (gas: 4372) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerExponentOverflowRescaleRevert(int256,int256,int256) (runs: 1707, μ: 13304, ~: 13218) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerExponentVeryLargeDiffRevert(int256,int256,int256) (runs: 5096, μ: 12115, ~: 12278) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerTargetExponentNoRevert(int256,int256,int256) (runs: 5096, μ: 10790, ~: 10703) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerExponentOverflowRescaleRevert(int256,int256,int256) (runs: 5096, μ: 7936, ~: 7937) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerExponentVeryLargeDiffRevert(int256,int256,int256) (runs: 5096, μ: 6784, ~: 6965) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerTargetExponentNoRevert(int256,int256,int256) (runs: 5096, μ: 2944, ~: 2859) LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentMaxOverflow(int256) (runs: 5096, μ: 594, ~: 594) LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentSameExponentNoop(int256,int256) (runs: 5096, μ: 549, ~: 549) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentScaleDown(int256,int256,int256) (runs: 5096, μ: 11554, ~: 11527) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentScaleUpLargeDiffRevert(int256,int256,int256) (runs: 5096, μ: 12292, ~: 12564) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentScaleUpNotOverflow(int256,int256,int256) (runs: 3401, μ: 12098, ~: 12082) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentScaleUpOverflow(int256,int256,int256) (runs: 1695, μ: 13055, ~: 13051) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentSmallerExponentNoRevert(int256,int256,int256) (runs: 3389, μ: 12410, ~: 12318) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentTargetMoreThan76Larger(int256,int256,int256) (runs: 5096, μ: 10886, ~: 10993) -LibDecimalFloatInvTest:testInvMem(bytes32) (runs: 5096, μ: 8055, ~: 8094) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentScaleDown(int256,int256,int256) (runs: 5096, μ: 3723, ~: 3706) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentScaleUpLargeDiffRevert(int256,int256,int256) (runs: 5096, μ: 6971, ~: 7158) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentScaleUpNotOverflow(int256,int256,int256) (runs: 5096, μ: 6782, ~: 6779) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentScaleUpOverflow(int256,int256,int256) (runs: 5096, μ: 7690, ~: 7663) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentSmallerExponentNoRevert(int256,int256,int256) (runs: 5096, μ: 7117, ~: 7015) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentTargetMoreThan76Larger(int256,int256,int256) (runs: 5096, μ: 3048, ~: 3067) +LibDecimalFloatInvTest:testInvMem(bytes32) (runs: 5096, μ: 7969, ~: 8094) LibDecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5096, μ: 1063, ~: 1063) LibDecimalFloatIsZeroTest:testIsZeroEqZero(bytes32) (runs: 5096, μ: 684, ~: 684) LibDecimalFloatIsZeroTest:testIsZeroExamples(int32) (runs: 5096, μ: 977, ~: 977) -LibDecimalFloatIsZeroTest:testNotIsZero(int224,int32) (runs: 5039, μ: 3592, ~: 3592) -LibDecimalFloatLog10Test:testLog10Packed(bytes32) (runs: 5096, μ: 1621253, ~: 1242793) +LibDecimalFloatIsZeroTest:testNotIsZero(int224,int32) (runs: 5096, μ: 3592, ~: 3592) +LibDecimalFloatLog10Test:testLog10Packed(bytes32) (runs: 5096, μ: 1706922, ~: 1245448) LibDecimalFloatLtTest:testLtExamples() (gas: 1161) LibDecimalFloatLtTest:testLtGasAZero() (gas: 953) LibDecimalFloatLtTest:testLtGasBZero() (gas: 1019) LibDecimalFloatLtTest:testLtGasBothZero() (gas: 944) LibDecimalFloatLtTest:testLtGasDifferentSigns() (gas: 1008) LibDecimalFloatLtTest:testLtGasExponentDiffOverflow() (gas: 1091) -LibDecimalFloatLtTest:testLtNegativeVsPositive(int256,int32,int256,int32) (runs: 5096, μ: 12162, ~: 12053) -LibDecimalFloatLtTest:testLtNegativeVsZero(int256,int32,int32) (runs: 5096, μ: 9604, ~: 9769) +LibDecimalFloatLtTest:testLtNegativeVsPositive(int256,int32,int256,int32) (runs: 5096, μ: 4287, ~: 4298) +LibDecimalFloatLtTest:testLtNegativeVsZero(int256,int32,int32) (runs: 5096, μ: 3023, ~: 3302) LibDecimalFloatLtTest:testLtOneEAny(int224,int32) (runs: 5096, μ: 1089, ~: 1090) -LibDecimalFloatLtTest:testLtReference(bytes32,bytes32) (runs: 5096, μ: 1822, ~: 2152) -LibDecimalFloatLtTest:testLtVsEqualVsGt(bytes32,bytes32) (runs: 5096, μ: 1473, ~: 1361) +LibDecimalFloatLtTest:testLtReference(bytes32,bytes32) (runs: 5096, μ: 2444, ~: 2250) +LibDecimalFloatLtTest:testLtVsEqualVsGt(bytes32,bytes32) (runs: 5096, μ: 1513, ~: 1361) LibDecimalFloatLtTest:testLtX(int224) (runs: 5096, μ: 981, ~: 982) -LibDecimalFloatLtTest:testLtXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 9482, ~: 9208) -LibDecimalFloatLtTest:testLtXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 9988, ~: 10138) +LibDecimalFloatLtTest:testLtXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 3202, ~: 3442) +LibDecimalFloatLtTest:testLtXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 3418, ~: 3671) LibDecimalFloatLtTest:testLtZero(int32,int32) (runs: 5096, μ: 1311, ~: 1311) LibDecimalFloatLteTest:testLteGasAZero() (gas: 1002) LibDecimalFloatLteTest:testLteGasBZero() (gas: 1004) @@ -265,52 +269,52 @@ LibDecimalFloatLteTest:testLteGasBothZero() (gas: 738) LibDecimalFloatLteTest:testLteGasDifferentSigns() (gas: 1013) LibDecimalFloatLteTest:testLteGasExponentDiffOverflow() (gas: 1118) LibDecimalFloatLteTest:testLteOneEAny(bytes32) (runs: 5096, μ: 657, ~: 657) -LibDecimalFloatLteTest:testLteReference(int224,int32,int224,int32) (runs: 5096, μ: 5349, ~: 3770) +LibDecimalFloatLteTest:testLteReference(int224,int32,int224,int32) (runs: 5096, μ: 8056, ~: 9010) LibDecimalFloatLteTest:testLteX(int224,int32) (runs: 5096, μ: 1088, ~: 1089) -LibDecimalFloatLteTest:testLteXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 9495, ~: 9220) -LibDecimalFloatLteTest:testLteXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 10000, ~: 10150) -LibDecimalFloatLteTest:testLteXNotLtY(bytes32,bytes32) (runs: 5096, μ: 1036, ~: 962) -LibDecimalFloatLteTest:testLteXPositiveYNegative(int256,int32,int256,int32) (runs: 5096, μ: 11799, ~: 11691) -LibDecimalFloatLteTest:testLteXPositiveYZero(int256,int32,int32) (runs: 5096, μ: 8796, ~: 8527) +LibDecimalFloatLteTest:testLteXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 3214, ~: 3454) +LibDecimalFloatLteTest:testLteXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 3430, ~: 3683) +LibDecimalFloatLteTest:testLteXNotLtY(bytes32,bytes32) (runs: 5096, μ: 1063, ~: 962) +LibDecimalFloatLteTest:testLteXPositiveYNegative(int256,int32,int256,int32) (runs: 5096, μ: 3934, ~: 3936) +LibDecimalFloatLteTest:testLteXPositiveYZero(int256,int32,int32) (runs: 5096, μ: 2503, ~: 2776) LibDecimalFloatLteTest:testLteZero(int32,int32) (runs: 5096, μ: 1632, ~: 1632) LibDecimalFloatMaxTest:testMaxX(bytes32) (runs: 5096, μ: 1105, ~: 1105) -LibDecimalFloatMaxTest:testMaxXY(bytes32,bytes32) (runs: 5096, μ: 1544, ~: 1468) +LibDecimalFloatMaxTest:testMaxXY(bytes32,bytes32) (runs: 5096, μ: 1570, ~: 1468) LibDecimalFloatMaxTest:testMaxXYEqual(bytes32) (runs: 5096, μ: 1511, ~: 1511) -LibDecimalFloatMaxTest:testMaxXYGreater(bytes32,bytes32) (runs: 2521, μ: 4864, ~: 4752) -LibDecimalFloatMaxTest:testMaxXYLess(bytes32,bytes32) (runs: 2572, μ: 4879, ~: 4763) +LibDecimalFloatMaxTest:testMaxXYGreater(bytes32,bytes32) (runs: 5096, μ: 4898, ~: 4752) +LibDecimalFloatMaxTest:testMaxXYLess(bytes32,bytes32) (runs: 5096, μ: 4922, ~: 4763) LibDecimalFloatMinTest:testMinX(bytes32) (runs: 5096, μ: 1127, ~: 1127) -LibDecimalFloatMinTest:testMinXY(bytes32,bytes32) (runs: 5096, μ: 1544, ~: 1468) +LibDecimalFloatMinTest:testMinXY(bytes32,bytes32) (runs: 5096, μ: 1570, ~: 1468) LibDecimalFloatMinTest:testMinXYEqual(bytes32) (runs: 5096, μ: 1531, ~: 1531) -LibDecimalFloatMinTest:testMinXYGreater(bytes32,bytes32) (runs: 2543, μ: 4809, ~: 4697) -LibDecimalFloatMinTest:testMinXYLess(bytes32,bytes32) (runs: 2550, μ: 4825, ~: 4708) -LibDecimalFloatMinusTest:testMinusPacked(bytes32) (runs: 5096, μ: 2418, ~: 2419) +LibDecimalFloatMinTest:testMinXYGreater(bytes32,bytes32) (runs: 5096, μ: 4847, ~: 4697) +LibDecimalFloatMinTest:testMinXYLess(bytes32,bytes32) (runs: 5096, μ: 4870, ~: 4708) +LibDecimalFloatMinusTest:testMinusPacked(bytes32) (runs: 5096, μ: 2417, ~: 2419) LibDecimalFloatMixedTest:testDiv1Over3Mixed() (gas: 7258) -LibDecimalFloatMulTest:testMulPacked(bytes32,bytes32) (runs: 5096, μ: 6789, ~: 7397) -LibDecimalFloatPackTest:testPackExponentOverflow(int256,int256) (runs: 5046, μ: 10285, ~: 10423) -LibDecimalFloatPackTest:testPackNegativeExponentLossyZero(int256,int256) (runs: 5046, μ: 10085, ~: 10201) +LibDecimalFloatMulTest:testMulPacked(bytes32,bytes32) (runs: 5096, μ: 6962, ~: 7451) +LibDecimalFloatPackTest:testPackExponentOverflow(int256,int256) (runs: 5096, μ: 6347, ~: 6519) +LibDecimalFloatPackTest:testPackNegativeExponentLossyZero(int256,int256) (runs: 5096, μ: 6088, ~: 6225) LibDecimalFloatPackTest:testPackZero(int256) (runs: 5096, μ: 654, ~: 654) LibDecimalFloatPackTest:testPartsRoundTrip(int224,int32) (runs: 5096, μ: 1021, ~: 1022) -LibDecimalFloatPow10Test:testPow10Packed(bytes32) (runs: 5096, μ: 1605231, ~: 1226366) -LibDecimalFloatPowTest:testNegativePowError(bytes32,bytes32) (runs: 5047, μ: 1216370, ~: 1216486) -LibDecimalFloatPowTest:testPowAZero(int32,bytes32) (runs: 3521, μ: 1215095, ~: 1215095) -LibDecimalFloatPowTest:testPowAZeroNegative(bytes32) (runs: 1628, μ: 1215967, ~: 1215967) -LibDecimalFloatPowTest:testPowBOne(bytes32) (runs: 5074, μ: 1423037, ~: 1423008) +LibDecimalFloatPow10Test:testPow10Packed(bytes32) (runs: 5096, μ: 1780209, ~: 1232182) +LibDecimalFloatPowTest:testNegativePowError(bytes32,bytes32) (runs: 5096, μ: 1216354, ~: 1216486) +LibDecimalFloatPowTest:testPowAZero(int32,bytes32) (runs: 5096, μ: 1215095, ~: 1215095) +LibDecimalFloatPowTest:testPowAZeroNegative(bytes32) (runs: 5096, μ: 1215967, ~: 1215967) +LibDecimalFloatPowTest:testPowBOne(bytes32) (runs: 5096, μ: 1423042, ~: 1423008) LibDecimalFloatPowTest:testPowBZero(bytes32,int32) (runs: 5096, μ: 1212165, ~: 1212165) LibDecimalFloatPowTest:testPows() (gas: 1649967) -LibDecimalFloatPowTest:testRoundTripFuzzPow(bytes32,bytes32) (runs: 5096, μ: 1260589, ~: 1236902) +LibDecimalFloatPowTest:testRoundTripFuzzPow(bytes32,bytes32) (runs: 5096, μ: 1235520, ~: 1212956) LibDecimalFloatPowTest:testRoundTripSimple() (gas: 1840934) -LibDecimalFloatSqrtTest:testRoundTripFuzzSqrt(int224,int32) (runs: 5096, μ: 1277051, ~: 1279819) -LibDecimalFloatSqrtTest:testSqrt() (gas: 1270465) -LibDecimalFloatSqrtTest:testSqrtNegative(bytes32) (runs: 5070, μ: 1216082, ~: 1216198) -LibDecimalFloatSqrtTest:testSqrtRoundTrip() (gas: 1487078) -LibDecimalFloatSubTest:testSubPacked(bytes32,bytes32) (runs: 5096, μ: 9327, ~: 9400) +LibDecimalFloatSqrtTest:testRoundTripFuzzSqrt(int224,int32) (runs: 5096, μ: 1271452, ~: 1278272) +LibDecimalFloatSqrtTest:testSqrt() (gas: 1270384) +LibDecimalFloatSqrtTest:testSqrtNegative(bytes32) (runs: 5096, μ: 1216063, ~: 1216198) +LibDecimalFloatSqrtTest:testSqrtRoundTrip() (gas: 1487094) +LibDecimalFloatSubTest:testSubPacked(bytes32,bytes32) (runs: 5096, μ: 8970, ~: 9348) LibFormatDecimalFloatCountSigFigs:testCountSigFigsExamples() (gas: 47425) -LibFormatDecimalFloatCountSigFigs:testCountSigFigsOne(int256) (runs: 5096, μ: 29890, ~: 30589) +LibFormatDecimalFloatCountSigFigs:testCountSigFigsOne(int256) (runs: 5096, μ: 22601, ~: 22120) LibFormatDecimalFloatCountSigFigs:testCountSigFigsZero(int256) (runs: 5096, μ: 520, ~: 520) LibFormatDecimalFloatToDecimalStringTest:testFormatDecimalExamples() (gas: 709867) -LibFormatDecimalFloatToDecimalStringTest:testFormatDecimalRoundTripExamples() (gas: 675555) -LibFormatDecimalFloatToDecimalStringTest:testFormatDecimalRoundTripNegative(int256,bool) (runs: 5096, μ: 60366, ~: 56707) -LibFormatDecimalFloatToDecimalStringTest:testFormatDecimalRoundTripNonNegative(uint256,bool) (runs: 5096, μ: 44916, ~: 47146) +LibFormatDecimalFloatToDecimalStringTest:testFormatDecimalRoundTripExamples() (gas: 675881) +LibFormatDecimalFloatToDecimalStringTest:testFormatDecimalRoundTripNegative(int256,bool) (runs: 5096, μ: 55659, ~: 52770) +LibFormatDecimalFloatToDecimalStringTest:testFormatDecimalRoundTripNonNegative(uint256,bool) (runs: 5096, μ: 41888, ~: 44041) LibLogTableBytesTest:testToBytesAntiLogTableDec() (gas: 153244) LibLogTableBytesTest:testToBytesAntiLogTableDecSmall() (gas: 158078) LibLogTableBytesTest:testToBytesLogTableDec() (gas: 137440) @@ -318,28 +322,28 @@ LibLogTableBytesTest:testToBytesLogTableDecSmall() (gas: 141832) LibLogTableBytesTest:testToBytesLogTableDecSmallAlt() (gas: 18046) LibParseDecimalFloatTest:testParseDecimalFloatEmpty() (gas: 979) LibParseDecimalFloatTest:testParseDecimalFloatExponentRevert() (gas: 973) -LibParseDecimalFloatTest:testParseDecimalFloatExponentRevert2() (gas: 2126) -LibParseDecimalFloatTest:testParseDecimalFloatExponentRevert3() (gas: 2232) +LibParseDecimalFloatTest:testParseDecimalFloatExponentRevert2() (gas: 2148) +LibParseDecimalFloatTest:testParseDecimalFloatExponentRevert3() (gas: 2254) LibParseDecimalFloatTest:testParseDecimalFloatExponentRevert4() (gas: 951) LibParseDecimalFloatTest:testParseDecimalFloatNonDecimal() (gas: 949) -LibParseDecimalFloatTest:testParseFormatterRoundTripBug0() (gas: 23065) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatDecimals() (gas: 324084) +LibParseDecimalFloatTest:testParseFormatterRoundTripBug0() (gas: 23152) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatDecimals() (gas: 326489) LibParseDecimalFloatTest:testParseLiteralDecimalFloatDotE() (gas: 970) LibParseDecimalFloatTest:testParseLiteralDecimalFloatDotE0() (gas: 971) LibParseDecimalFloatTest:testParseLiteralDecimalFloatDotRevert() (gas: 949) LibParseDecimalFloatTest:testParseLiteralDecimalFloatDotRevert2() (gas: 971) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatDotRevert3() (gas: 1933) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatDotRevert3() (gas: 1955) LibParseDecimalFloatTest:testParseLiteralDecimalFloatEDot() (gas: 972) LibParseDecimalFloatTest:testParseLiteralDecimalFloatExponentRevert5() (gas: 980) LibParseDecimalFloatTest:testParseLiteralDecimalFloatExponentRevert6() (gas: 970) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatExponents() (gas: 317178) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatFuzz(uint256,uint8,bool) (runs: 5096, μ: 41818, ~: 32939) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatLeadingZeros() (gas: 47119) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatNegativeE() (gas: 2777) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatNegativeFrac() (gas: 1908) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatPrecisionRevert0() (gas: 24357) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatPrecisionRevert1() (gas: 21563) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatSpecific() (gas: 12124) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatUnrelated() (gas: 34617) -LibParseDecimalFloatTest:testParsePacked(string) (runs: 5096, μ: 5024, ~: 4970) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatExponents() (gas: 321070) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatFuzz(uint256,uint8,bool) (runs: 5096, μ: 33846, ~: 27205) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatLeadingZeros() (gas: 47427) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatNegativeE() (gas: 2799) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatNegativeFrac() (gas: 1930) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatPrecisionRevert0() (gas: 24401) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatPrecisionRevert1() (gas: 21607) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatSpecific() (gas: 12389) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatUnrelated() (gas: 35350) +LibParseDecimalFloatTest:testParsePacked(string) (runs: 5096, μ: 6164, ~: 5242) TestDecimalFloatUnpackTest:testUnpackDeployed(bytes32) (runs: 5096, μ: 163108, ~: 163108) \ No newline at end of file diff --git a/.github/workflows/manual-sol-artifacts.yaml b/.github/workflows/manual-sol-artifacts.yaml index 10a6bb9..f85e854 100644 --- a/.github/workflows/manual-sol-artifacts.yaml +++ b/.github/workflows/manual-sol-artifacts.yaml @@ -72,6 +72,8 @@ jobs: DEPLOY_BROADCAST: '1' DEPLOYMENT_KEY: ${{ github.ref == 'refs/heads/main' && secrets.PRIVATE_KEY || secrets.PRIVATE_KEY_DEV }} ETH_RPC_URL: ${{ secrets[env.rpc_secret_name] || vars[env.rpc_secret_name] || '' }} + CI_FORK_ETH_RPC_URL: ${{ secrets.RPC_URL_ETHEREUM_FORK || vars.RPC_URL_ETHEREUM_FORK || '' }} + CI_FORK_FLARE_RPC_URL: ${{ secrets.RPC_URL_FLARE_FORK || vars.RPC_URL_FLARE_FORK || '' }} ETHERSCAN_API_KEY: ${{ secrets[env.etherscan_api_key_secret_name] || vars[env.etherscan_api_key_secret_name] || ''}} DEPLOY_VERIFY: ${{ secrets[env.verify_secret_name] || vars[env.verify_secret_name] || '' }} DEPLOY_VERIFIER: ${{ secrets[env.verifier_secret_name] || vars[env.verifier_secret_name] || '' }} diff --git a/.github/workflows/rainix.yaml b/.github/workflows/rainix.yaml index 3033106..33a1a45 100644 --- a/.github/workflows/rainix.yaml +++ b/.github/workflows/rainix.yaml @@ -54,6 +54,10 @@ jobs: - name: Run ${{ matrix.task }} env: ETH_RPC_URL: ${{ secrets.CI_DEPLOY_SEPOLIA_RPC_URL || vars.CI_DEPLOY_SEPOLIA_RPC_URL }} + CI_FORK_ARB_RPC_URL: ${{ secrets.RPC_URL_ARBITRUM_FORK || vars.RPC_URL_ARBITRUM_FORK || '' }} + CI_FORK_ETH_RPC_URL: ${{ secrets.RPC_URL_ETHEREUM_FORK || vars.RPC_URL_ETHEREUM_FORK || '' }} + CI_FORK_BASE_RPC_URL: ${{ secrets.RPC_URL_BASE_FORK || vars.RPC_URL_BASE_FORK || '' }} + CI_FORK_FLARE_RPC_URL: ${{ secrets.RPC_URL_FLARE_FORK || vars.RPC_URL_FLARE_FORK || '' }} ETHERSCAN_API_KEY: ${{ secrets.EXPLORER_VERIFICATION_KEY }} DEPLOY_BROADCAST: "" DEPLOY_VERIFIER: "" diff --git a/.gitignore b/.gitignore index 01d487d..fcb4b97 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ target temp dist node_modules +.env \ No newline at end of file diff --git a/flake.lock b/flake.lock index 894a168..9a12e0c 100644 --- a/flake.lock +++ b/flake.lock @@ -75,11 +75,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1758705030, - "narHash": "sha256-zYM8PiEXANNrtjfyGUc7w37/D/kCynp0cQS+wCQ77GI=", + "lastModified": 1769324704, + "narHash": "sha256-aef15vEgiMEls1hTMt46rJuKNSO2cIOfiP99patq9yc=", "owner": "shazow", "repo": "foundry.nix", - "rev": "b59a55014050110170023e3e1c277c1d4a2f055b", + "rev": "e830409ba1bdecdc5ef9a1ec92660fc2da9bc68d", "type": "github" }, "original": { @@ -102,13 +102,29 @@ "type": "indirect" } }, + "nixpkgs-old": { + "locked": { + "lastModified": 1749104371, + "narHash": "sha256-m2NmOPd6XgBiskmUq/BS9Xxuf3z0ebnGVfSKNAO5NEM=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "48975d7f9b9960ed33c4e8561bcce20cc0c2de5b", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "rev": "48975d7f9b9960ed33c4e8561bcce20cc0c2de5b", + "type": "github" + } + }, "nixpkgs_2": { "locked": { - "lastModified": 1758711836, - "narHash": "sha256-uBqPg7wNX2v6YUdTswH7wWU8wqb60cFZx0tHaWTGF30=", + "lastModified": 1769364508, + "narHash": "sha256-Wy8EVYSLq5Fb/rYH3LRxAMCnW75f9hOg2562AXVFmPk=", "owner": "nixos", "repo": "nixpkgs", - "rev": "46f97b78e825ae762c0224e3983c47687436a498", + "rev": "6077bc4fb29be43d525984f63b69d37b9b1e62fe", "type": "github" }, "original": { @@ -135,11 +151,11 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1748662220, - "narHash": "sha256-7gGa49iB9nCnFk4h/g9zwjlQAyjtpgcFkODjcOQS0Es=", + "lastModified": 1766653575, + "narHash": "sha256-TPgxCS7+hWc4kPhzkU5dD2M5UuPhLuuaMNZ/IpwKQvI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "59138c7667b7970d205d6a05a8bfa2d78caa3643", + "rev": "3c1016e6acd16ad96053116d0d3043029c9e2649", "type": "github" }, "original": { @@ -154,15 +170,16 @@ "flake-utils": "flake-utils_2", "foundry": "foundry", "nixpkgs": "nixpkgs_2", + "nixpkgs-old": "nixpkgs-old", "rust-overlay": "rust-overlay", "solc": "solc" }, "locked": { - "lastModified": 1760460761, - "narHash": "sha256-IHvwnmphDaOyZnzvObwOoDQlA9nzym2ZUxe9K/5vs0U=", + "lastModified": 1769366341, + "narHash": "sha256-jeYOweTuJdKshW9lqVoNxvl4+flyRzWxEctRGabTW/8=", "owner": "rainprotocol", "repo": "rainix", - "rev": "add0d8a1fd76ce0e65b962c952e9252257876465", + "rev": "e7bfe9c39d2de818eac241f88ecabc69e86ed734", "type": "github" }, "original": { @@ -182,11 +199,11 @@ "nixpkgs": "nixpkgs_3" }, "locked": { - "lastModified": 1758681214, - "narHash": "sha256-8cW731vev6kfr58cILO2ZsjHwaPhm88dQ8Q6nTSjP9I=", + "lastModified": 1769309768, + "narHash": "sha256-AbOIlNO+JoqRJkK1VrnDXhxuX6CrdtIu2hSuy4pxi3g=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "b12ed88d8d33d4f3cbc842bf29fad93bb1437299", + "rev": "140c9dc582cb73ada2d63a2180524fcaa744fad5", "type": "github" }, "original": { @@ -202,11 +219,11 @@ "solc-macos-amd64-list-json": "solc-macos-amd64-list-json" }, "locked": { - "lastModified": 1756368702, - "narHash": "sha256-cqEHv7uCV0LibmQphyiXZ1+jYtGjMNb9Pae4tfcAcF8=", + "lastModified": 1768831671, + "narHash": "sha256-0mmlYRtZK+eomevkQCCH7PL8QlSuALZQsjLroCWGE08=", "owner": "hellwolf", "repo": "solc.nix", - "rev": "d83e90df2fa8359a690f6baabf76099432193c3f", + "rev": "80ad871b93d15c7bccf71617f78f73c2d291a9c7", "type": "github" }, "original": { @@ -218,13 +235,13 @@ "solc-macos-amd64-list-json": { "flake": false, "locked": { - "narHash": "sha256-AvITkfpNYgCypXuLJyqco0li+unVw39BAfdOZvd/SPE=", + "narHash": "sha256-P+ZslplK4cQ/wnV/wykVKb+yTCviI0eylA3sk9uHmRo=", "type": "file", - "url": "https://github.com/argotorg/solc-bin/raw/26fc3fd/macosx-amd64/list.json" + "url": "https://github.com/argotorg/solc-bin/raw/a11f1ad/macosx-amd64/list.json" }, "original": { "type": "file", - "url": "https://github.com/argotorg/solc-bin/raw/26fc3fd/macosx-amd64/list.json" + "url": "https://github.com/argotorg/solc-bin/raw/a11f1ad/macosx-amd64/list.json" } }, "systems": { diff --git a/foundry.lock b/foundry.lock index c03a15c..f927c02 100644 --- a/foundry.lock +++ b/foundry.lock @@ -1,17 +1,17 @@ { "lib/forge-std": { - "rev": "b8f065fda83b8cd94a6b2fec8fcd911dc3b444fd" + "rev": "1801b0541f4fda118a10798fd3486bb7051c5dd6" }, "lib/rain.datacontract": { "rev": "061bf7cd63496ccbe4f74bcd0c48715883c1c3cb" }, "lib/rain.math.fixedpoint": { - "rev": "1752e9fbd635901ac7eb177699681ed97290e12e" + "rev": "8308cbb6da0e231c6f3437f1861e66eff7ea2b00" }, "lib/rain.sol.codegen": { "rev": "bd7993b3f6b301e5a667ff687f25b80fdda878cd" }, "lib/rain.string": { - "rev": "0b1ca08aed6d9c06b83fe127a7d20ee7002ead28" + "rev": "488f237cd59874e4eb91b5a4f747bd57578fec7f" } } \ No newline at end of file diff --git a/lib/forge-std b/lib/forge-std index b8f065f..1801b05 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit b8f065fda83b8cd94a6b2fec8fcd911dc3b444fd +Subproject commit 1801b0541f4fda118a10798fd3486bb7051c5dd6 diff --git a/lib/rain.math.fixedpoint b/lib/rain.math.fixedpoint index 1752e9f..8308cbb 160000 --- a/lib/rain.math.fixedpoint +++ b/lib/rain.math.fixedpoint @@ -1 +1 @@ -Subproject commit 1752e9fbd635901ac7eb177699681ed97290e12e +Subproject commit 8308cbb6da0e231c6f3437f1861e66eff7ea2b00 diff --git a/lib/rain.string b/lib/rain.string index 0b1ca08..488f237 160000 --- a/lib/rain.string +++ b/lib/rain.string @@ -1 +1 @@ -Subproject commit 0b1ca08aed6d9c06b83fe127a7d20ee7002ead28 +Subproject commit 488f237cd59874e4eb91b5a4f747bd57578fec7f diff --git a/src/concrete/DecimalFloat.sol b/src/concrete/DecimalFloat.sol index 23ca543..b50e226 100644 --- a/src/concrete/DecimalFloat.sol +++ b/src/concrete/DecimalFloat.sol @@ -67,7 +67,9 @@ contract DecimalFloat { } /// Exposes `LibFormatDecimalFloat.toDecimalString` for offchain use. - /// @param a The float to format. + /// @param a The float to format. The absolute value of `a` is used to + /// determine if scientific notation is used, this allows negative numbers to + /// be formatted consistently with their positive counterparts. /// @param scientificMin The smallest number that won't be formatted in /// scientific notation. /// @param scientificMax The largest number that won't be formatted in @@ -75,7 +77,8 @@ contract DecimalFloat { /// @return The string representation of the float. function format(Float a, Float scientificMin, Float scientificMax) public pure returns (string memory) { require(scientificMin.lt(scientificMax), "scientificMin must be less than scientificMax"); - return LibFormatDecimalFloat.toDecimalString(a, a.lt(scientificMin) || a.gt(scientificMax)); + Float absA = a.abs(); + return LibFormatDecimalFloat.toDecimalString(a, absA.lt(scientificMin) || absA.gt(scientificMax)); } /// Exposes `LibFormatDecimalFloat.toDecimalString` for offchain use. diff --git a/src/error/ErrDecimalFloat.sol b/src/error/ErrDecimalFloat.sol index 8f2a8ac..708c8dd 100644 --- a/src/error/ErrDecimalFloat.sol +++ b/src/error/ErrDecimalFloat.sol @@ -44,3 +44,6 @@ error DivisionByZero(int256 signedCoefficient, int256 exponent); /// @dev Thrown when attempting to exponentiate a negative base. error PowNegativeBase(int256 signedCoefficient, int256 exponent); + +/// @dev Thrown if writing the data by creating the contract fails somehow. +error WriteError(); diff --git a/src/lib/LibDecimalFloat.sol b/src/lib/LibDecimalFloat.sol index 54d4668..a207232 100644 --- a/src/lib/LibDecimalFloat.sol +++ b/src/lib/LibDecimalFloat.sol @@ -44,6 +44,9 @@ type Float is bytes32; library LibDecimalFloat { using LibDecimalFloat for Float; + /// Address of the log tables data contract. Only valid if deployed using + /// the standard Rain deployment scripts that use Zoltu deterministic + /// deployment. address constant LOG_TABLES_ADDRESS = 0x6421E8a23cdEe2E6E579b2cDebc8C2A514843593; /// A zero valued float. @@ -347,6 +350,11 @@ library LibDecimalFloat { } } + /// Lossless version of `packLossy`. This will revert if the conversion is + /// lossy. + /// @param signedCoefficient As per `packLossy`. + /// @param exponent As per `packLossy`. + /// @return float As per `packLossy`. function packLossless(int256 signedCoefficient, int256 exponent) internal pure returns (Float) { (Float c, bool lossless) = packLossy(signedCoefficient, exponent); if (!lossless) { @@ -573,16 +581,15 @@ library LibDecimalFloat { /// @param float The float to frac. function frac(Float float) internal pure returns (Float) { (int256 signedCoefficient, int256 exponent) = float.unpack(); - (int256 characteristic, int256 mantissa) = - LibDecimalFloatImplementation.characteristicMantissa(signedCoefficient, exponent); - (characteristic); - (Float result, bool lossless) = packLossy(mantissa, exponent); + (int256 integer, int256 fraction) = LibDecimalFloatImplementation.intFrac(signedCoefficient, exponent); + (integer); + (Float result, bool lossless) = packLossy(fraction, exponent); // Frac is lossy by definition. (lossless); return result; } - /// Integer component of a float. + /// Smallest integer value less than or equal to the float. /// @param float The float to floor. function floor(Float float) internal pure returns (Float) { (int256 signedCoefficient, int256 exponent) = float.unpack(); @@ -590,11 +597,15 @@ library LibDecimalFloat { if (exponent >= 0) { return float; } - (int256 characteristic, int256 mantissa) = - LibDecimalFloatImplementation.characteristicMantissa(signedCoefficient, exponent); - (Float result, bool lossless) = packLossy(characteristic, exponent); + (int256 integer, int256 fraction) = LibDecimalFloatImplementation.intFrac(signedCoefficient, exponent); + if (signedCoefficient < 0 && fraction != 0) { + // If the float is negative and has a fractional part, we need to + // subtract 1 from the characteristic to floor it. + (integer, exponent) = LibDecimalFloatImplementation.sub(integer, exponent, 1e76, -76); + } + (Float result, bool lossless) = packLossy(integer, exponent); // Flooring is lossy by definition. - (lossless, mantissa); + (lossless, fraction); return result; } @@ -606,22 +617,21 @@ library LibDecimalFloat { if (exponent >= 0) { return float; } - (int256 characteristic, int256 mantissa) = - LibDecimalFloatImplementation.characteristicMantissa(signedCoefficient, exponent); + (int256 integer, int256 fraction) = LibDecimalFloatImplementation.intFrac(signedCoefficient, exponent); - // If the mantissa is 0, then the float is already an integer. - if (mantissa == 0) { + // If the fraction is 0, then the float is already an integer. + if (fraction == 0) { return float; } // Truncate the fractional part when exponent < 0: - // mantissa < 0 (input < 0) → truncation towards zero increases the value (correct ceil). - // mantissa == 0 → value is already an integer. - // mantissa > 0 (input > 0) → truncation decreases the value, so add 1 to round up. - else if (mantissa > 0) { - (characteristic, exponent) = LibDecimalFloatImplementation.add(characteristic, exponent, 1e76, -76); + // fraction < 0 (input < 0) → truncation towards zero increases the value (correct ceil). + // fraction == 0 → value is already an integer. + // fraction > 0 (input > 0) → truncation decreases the value, so add 1 to round up. + else if (fraction > 0) { + (integer, exponent) = LibDecimalFloatImplementation.add(integer, exponent, 1e76, -76); } - (Float result, bool lossless) = packLossy(characteristic, exponent); + (Float result, bool lossless) = packLossy(integer, exponent); (lossless); return result; } @@ -700,11 +710,9 @@ library LibDecimalFloat { } (int256 signedCoefficientB, int256 exponentB) = b.unpack(); - (int256 characteristicB, int256 mantissaB) = - LibDecimalFloatImplementation.characteristicMantissa(signedCoefficientB, exponentB); + (int256 integerB, int256 fractionB) = LibDecimalFloatImplementation.intFrac(signedCoefficientB, exponentB); - uint256 exponentBInteger = - uint256(LibDecimalFloatImplementation.withTargetExponent(characteristicB, exponentB, 0)); + uint256 exponentBInteger = uint256(LibDecimalFloatImplementation.withTargetExponent(integerB, exponentB, 0)); // Exponentiation by squaring. (int256 signedCoefficientResult, int256 exponentResult) = (1, 0); @@ -725,7 +733,7 @@ library LibDecimalFloat { LibDecimalFloatImplementation.log10(tablesDataContract, signedCoefficientA, exponentA); (signedCoefficientC, exponentC) = - LibDecimalFloatImplementation.mul(signedCoefficientC, exponentC, mantissaB, exponentB); + LibDecimalFloatImplementation.mul(signedCoefficientC, exponentC, fractionB, exponentB); (signedCoefficientC, exponentC) = LibDecimalFloatImplementation.pow10(tablesDataContract, signedCoefficientC, exponentC); @@ -772,6 +780,9 @@ library LibDecimalFloat { return gt(a, b) ? a : b; } + /// Returns true if the float is zero. Handles the case where the signed + /// coefficient is zero and exponent is potentially non zero. + /// @param a The float to check. function isZero(Float a) internal pure returns (bool result) { uint256 mask = type(uint224).max; assembly ("memory-safe") { diff --git a/src/lib/deploy/LibDecimalFloatDeploy.sol b/src/lib/deploy/LibDecimalFloatDeploy.sol index 5995a60..eb73668 100644 --- a/src/lib/deploy/LibDecimalFloatDeploy.sol +++ b/src/lib/deploy/LibDecimalFloatDeploy.sol @@ -14,8 +14,27 @@ import {LibBytes} from "rain.solmem/lib/LibBytes.sol"; import {LibMemCpy, Pointer} from "rain.solmem/lib/LibMemCpy.sol"; import {DecimalFloat} from "../../concrete/DecimalFloat.sol"; import {LOG_TABLE_DISAMBIGUATOR} from "../table/LibLogTable.sol"; +import {WriteError} from "../../error/ErrDecimalFloat.sol"; library LibDecimalFloatDeploy { + /// @dev Zoltu deterministic deployment proxy address. + /// https://github.com/Zoltu/deterministic-deployment-proxy?tab=readme-ov-file#proxy-address + address constant ZOLTU_PROXY_ADDRESS = 0x7A0D94F55792C434d74a40883C6ed8545E406D12; + + /// @dev Address of the DecimalFloat contract deployed via Zoltu's + /// deterministic deployment proxy. + /// This address is the same across all EVM-compatible networks. + address constant ZOLTU_DEPLOYED_DECIMAL_FLOAT_ADDRESS = address(0x6421E8a23cdEe2E6E579b2cDebc8C2A514843593); + + /// @dev The expected codehash of the DecimalFloat contract deployed via + /// Zoltu's deterministic deployment proxy. + bytes32 constant DECIMAL_FLOAT_DATA_CONTRACT_HASH = + 0x2573004ac3a9ee7fc8d73654d76386f1b6b99e34cdf86a689c4691e47143420f; + + /// Combines all log and anti-log tables into a single bytes array for + /// deployment. These are using packed encoding to minimize size and remove + /// the complexity of full ABI encoding. + /// @return The combined tables. function combinedTables() internal pure returns (bytes memory) { return abi.encodePacked( LOG_TABLES, @@ -27,6 +46,10 @@ library LibDecimalFloatDeploy { ); } + /// Creates a DataContractMemoryContainer containing all log and anti-log + /// tables. + /// @return dataContract The DataContractMemoryContainer containing the + /// tables. function dataContract() internal pure returns (DataContractMemoryContainer) { bytes memory tables = combinedTables(); (DataContractMemoryContainer container, Pointer pointer) = LibDataContract.newContainer(tables.length); @@ -34,17 +57,22 @@ library LibDecimalFloatDeploy { return container; } + /// Deploys a DecimalFloat contract using Zoltu's deterministic deployment + /// proxy contract. This allows the concrete DecimalFloat contract to be + /// found at a predictable location regardless of the network. + /// Reverts with WriteError if deployment fails. + /// @return deployedAddress The address of the deployed DecimalFloat + /// contract. function decimalFloatZoltu() internal returns (DecimalFloat deployedAddress) { //slither-disable-next-line too-many-digits bytes memory code = type(DecimalFloat).creationCode; bool success; + address zoltuProxy = ZOLTU_PROXY_ADDRESS; assembly ("memory-safe") { mstore(0, 0) - success := call(gas(), 0x7A0D94F55792C434d74a40883C6ed8545E406D12, 0, add(code, 0x20), mload(code), 12, 20) + success := call(gas(), zoltuProxy, 0, add(code, 0x20), mload(code), 12, 20) deployedAddress := mload(0) } - if (!success) { - revert("DecimalFloat: deploy failed"); - } + if (address(deployedAddress) == address(0) || !success) revert WriteError(); } } diff --git a/src/lib/format/LibFormatDecimalFloat.sol b/src/lib/format/LibFormatDecimalFloat.sol index 7f24811..72930c5 100644 --- a/src/lib/format/LibFormatDecimalFloat.sol +++ b/src/lib/format/LibFormatDecimalFloat.sol @@ -3,14 +3,18 @@ pragma solidity ^0.8.25; import {LibDecimalFloat, Float} from "../LibDecimalFloat.sol"; - import {LibDecimalFloatImplementation} from "../../lib/implementation/LibDecimalFloatImplementation.sol"; - import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; - import {UnformatableExponent} from "../../error/ErrFormat.sol"; +/// @dev Library for formatting DecimalFloat values as strings. +/// Not particularly efficient as it is intended for offchain use that doesn't +/// cost gas. library LibFormatDecimalFloat { + /// Counts the number of significant figures in a decimal float. + /// @param signedCoefficient The signed coefficient of the decimal float. + /// @param exponent The exponent of the decimal float. + /// @return sigFigs The number of significant figures. function countSigFigs(int256 signedCoefficient, int256 exponent) internal pure returns (uint256) { if (signedCoefficient == 0) { return 1; diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index 5212a27..81b737e 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -17,28 +17,38 @@ import { ANTILOG_IDX_LAST_INDEX } from "../table/LibLogTable.sol"; +/// @dev Thrown when attempting to rescale a coefficient to a target exponent error WithTargetExponentOverflow(int256 signedCoefficient, int256 exponent, int256 targetExponent); +/// @dev The maximum difference in exponents when adding to rescale. uint256 constant ADD_MAX_EXPONENT_DIFF = 76; /// @dev The maximum exponent that can be maximized. /// This is crazy large, so should never be a problem for any real use case. /// We need it to guard against overflow when maximizing. int256 constant EXPONENT_MAX = type(int256).max / 2; -int256 constant EXPONENT_MAX_PLUS_ONE = EXPONENT_MAX + 1; -/// @dev The minimum exponent that can be normalized. +/// @dev The minimum exponent that can be maximized. /// This is crazy small, so should never be a problem for any real use case. -/// We need it to guard against overflow when normalizing. +/// We need it to guard against overflow when maximized. int256 constant EXPONENT_MIN = -EXPONENT_MAX; /// @dev The signed coefficient of maximized zero. int256 constant MAXIMIZED_ZERO_SIGNED_COEFFICIENT = 0; + /// @dev The exponent of maximized zero. int256 constant MAXIMIZED_ZERO_EXPONENT = 0; +/// @dev The exponent used in log10 calculations to get the correct result +/// when using the log tables. int256 constant LOG10_Y_EXPONENT = -76; +/// @dev Library implementing core DecimalFloat operations using only stack +/// variables. +/// NOT intended for external use, typical use is to treat the `Float` type +/// as the interface to the float functionality. The tradeoff is better +/// abstractions for some more gas and less range of the operations due to +/// packing and unpacking having fundamental bit size limitations. library LibDecimalFloatImplementation { /// Negates a float. /// Equivalent to `0 - x`. @@ -72,6 +82,10 @@ library LibDecimalFloatImplementation { } } + /// Returns the absolute value of a signed coefficient as an unsigned + /// integer. + /// @param signedCoefficient The signed coefficient. + /// @return The absolute value as an unsigned integer. function absUnsignedSignedCoefficient(int256 signedCoefficient) internal pure returns (uint256) { unchecked { if (signedCoefficient < 0) { @@ -90,6 +104,15 @@ library LibDecimalFloatImplementation { } } + /// Given the absolute value of the result coefficient, and the signs of + /// the input coefficients, returns the signed coefficient and exponent of + /// the result of a multiplication or division operation. + /// @param a The signed coefficient of the first operand. + /// @param b The signed coefficient of the second operand. + /// @param signedCoefficientAbs The absolute value of the result coefficient. + /// @param exponent The exponent of the result. + /// @return signedCoefficient The signed coefficient of the result. + /// @return exponent The exponent of the result. function unabsUnsignedMulOrDivLossy(int256 a, int256 b, uint256 signedCoefficientAbs, int256 exponent) internal pure @@ -128,6 +151,12 @@ library LibDecimalFloatImplementation { } /// Stack only implementation of `mul`. + /// @param signedCoefficientA The signed coefficient of the first operand. + /// @param exponentA The exponent of the first operand. + /// @param signedCoefficientB The signed coefficient of the second operand. + /// @param exponentB The exponent of the second operand. + /// @return signedCoefficient The signed coefficient of the result. + /// @return exponent The exponent of the result. function mul(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB) internal pure @@ -362,6 +391,9 @@ library LibDecimalFloatImplementation { adjustExponent -= 1; } } + if (scale == 0) { + revert MaximizeOverflow(signedCoefficientB, exponentB); + } } if (!fullA) { revert MaximizeOverflow(signedCoefficientA, exponentA); @@ -705,6 +737,10 @@ library LibDecimalFloatImplementation { return div(1e76, -76, signedCoefficient, exponent); } + /// Looks up the log10 table value for a given index. + /// @param tables The address of the log tables data contract. + /// @param index The index into the log table. + /// @return result The log10 table value. function lookupLogTableVal(address tables, uint256 index) internal view returns (uint256 result) { // Skip first byte of data contract. uint256 smallTableOffset = LOG_TABLE_SIZE_BYTES + 1; @@ -720,7 +756,9 @@ library LibDecimalFloatImplementation { let mainTableVal := mload(0) result := and(mainTableVal, 0x7FFF) - if iszero(iszero(and(mainTableVal, 0x8000))) { smallTableOffset := add(smallTableOffset, logTableSizeBase) } + if iszero(iszero(and(mainTableVal, 0x8000))) { + smallTableOffset := add(smallTableOffset, logTableSizeBase) + } mstore(0, 0) // truncation from the div by 100 is intentional here to keep the @@ -873,11 +911,10 @@ library LibDecimalFloatImplementation { } // Table lookup. - (int256 characteristicCoefficient, int256 mantissaCoefficient) = - characteristicMantissa(signedCoefficient, exponent); + (int256 intCoefficient, int256 fracCoefficient) = intFrac(signedCoefficient, exponent); int256 characteristicExponent = exponent; { - (int256 idx, bool interpolate, int256 scale) = mantissa4(mantissaCoefficient, exponent); + (int256 idx, bool interpolate, int256 scale) = mantissa4(fracCoefficient, exponent); // idx is positive here because the signedCoefficient is positive due // to the opening `if` above. int256 y1Coefficient = 9997; @@ -885,7 +922,7 @@ library LibDecimalFloatImplementation { if (idx != ANTILOG_IDX_LAST_INDEX) { (y1Coefficient, y2Coefficient) = // forge-lint: disable-next-line(unsafe-typecast) - lookupAntilogTableY1Y2(tablesDataContract, uint256(idx), interpolate); + lookupAntilogTableY1Y2(tablesDataContract, uint256(idx), interpolate); } if (interpolate) { // This avoids a potential overflow below. @@ -893,12 +930,12 @@ library LibDecimalFloatImplementation { unchecked { while ((idxPlus1 * scale) / scale != idxPlus1) { scale /= 10; - mantissaCoefficient /= 10; + fracCoefficient /= 10; } } (signedCoefficient, exponent) = unitLinearInterpolation( - idx * scale, mantissaCoefficient, idxPlus1 * scale, exponent, y1Coefficient, y2Coefficient, -4 + idx * scale, fracCoefficient, idxPlus1 * scale, exponent, y1Coefficient, y2Coefficient, -4 ); } else { signedCoefficient = y1Coefficient; @@ -906,10 +943,13 @@ library LibDecimalFloatImplementation { } } - return - (signedCoefficient, 1 + exponent + withTargetExponent(characteristicCoefficient, characteristicExponent, 0)); + return (signedCoefficient, 1 + exponent + withTargetExponent(intCoefficient, characteristicExponent, 0)); } + /// Maximizes a float's signed coefficient by increasing its magnitude + /// and decreasing its exponent accordingly. Greatly simplified a lot of + /// internal logic that involves comparing signed coefficients as integers, + /// or wanting them to have comparable magnitudes. /// @return signedCoefficient The maximized signed coefficient. /// @return exponent The maximized exponent. /// @return full `true` if the result is fully maximized, `false` if it was @@ -962,6 +1002,12 @@ library LibDecimalFloatImplementation { } } + /// Maximizes a float as per `maximize` but errors if not fully maximized. + /// This is analogous to other functions in the lib that are "lossless". + /// @param signedCoefficient The signed coefficient. + /// @param exponent The exponent. + /// @return signedCoefficient The maximized signed coefficient. + /// @return exponent The maximized exponent. function maximizeFull(int256 signedCoefficient, int256 exponent) internal pure returns (int256, int256) { (int256 trySignedCoefficient, int256 tryExponent, bool full) = maximize(signedCoefficient, exponent); if (!full) { @@ -1012,17 +1058,16 @@ library LibDecimalFloatImplementation { { bool noopRescale; assembly ("memory-safe") { - noopRescale := + noopRescale := or( 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) - ) + // 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); @@ -1112,20 +1157,25 @@ library LibDecimalFloatImplementation { } } - function characteristicMantissa(int256 signedCoefficient, int256 exponent) - internal - pure - returns (int256 characteristic, int256 mantissa) - { + /// Returns the integer and fractional parts of a float. Both parts retain + /// the sign and exponent of the input float such that integer + frac = + /// original float. For all non negative exponents, frac is 0 and the integer + /// part is the original float. For exponents less than -76, the corollary is + /// true: integer is always 0 and frac is the original float. + /// @param signedCoefficient The signed coefficient. + /// @param exponent The exponent. + /// @return integer The integer part of the float. + /// @return frac The fractional part of the float. + function intFrac(int256 signedCoefficient, int256 exponent) internal pure returns (int256 integer, int256 frac) { unchecked { - // if exponent is not negative the characteristic is the number - // itself and the mantissa is 0. + // if exponent is not negative the integer part is the number + // itself and the fractional part is 0. if (exponent >= 0) { return (signedCoefficient, 0); } - // If the exponent is less than -76, the characteristic is 0. - // and the mantissa is the whole coefficient. + // If the exponent is less than -76, the integer part is 0. + // and the fractional part is the whole coefficient. if (exponent < -76) { return (0, signedCoefficient); } @@ -1133,12 +1183,17 @@ library LibDecimalFloatImplementation { // exponent [-76, -1] // forge-lint: disable-next-line(unsafe-typecast) int256 unit = int256(10 ** uint256(-exponent)); - mantissa = signedCoefficient % unit; - characteristic = signedCoefficient - mantissa; + frac = signedCoefficient % unit; + integer = signedCoefficient - frac; } } /// First 4 digits of the mantissa and whether we need to interpolate. + /// @param signedCoefficient The signed coefficient. + /// @param exponent The exponent. + /// @return mantissa The first 4 digits of the mantissa. + /// @return interpolate `true` if we need to interpolate, `false` otherwise. + /// @return scale The scale used if we need to interpolate. function mantissa4(int256 signedCoefficient, int256 exponent) internal pure returns (int256, bool, int256) { unchecked { if (exponent == -4) { @@ -1161,6 +1216,13 @@ library LibDecimalFloatImplementation { } } + /// Looks up the antilog table values y1 and y2 for a given index. + /// @param tablesDataContract The address of the log tables data contract. + /// @param idx The index into the antilog table. + /// @param lossyIdx `true` if the index may be lossy and we need y2, `false` + /// otherwise. + /// @return y1Coefficient The y1 antilog table coefficient. + /// @return y2Coefficient The y2 antilog table coefficient. // forge-lint: disable-next-line(mixed-case-function) function lookupAntilogTableY1Y2(address tablesDataContract, uint256 idx, bool lossyIdx) internal @@ -1191,8 +1253,17 @@ library LibDecimalFloatImplementation { } } - // Linear interpolation. - // y = y1 + ((x - x1) * (y2 - y1)) / (x2 - x1) + /// Linear interpolation. + /// y = y1 + ((x - x1) * (y2 - y1)) / (x2 - x1) + /// @param x1Coefficient The x1 coefficient. + /// @param xCoefficient The x coefficient. + /// @param x2Coefficient The x2 coefficient. + /// @param xExponent The x exponent. + /// @param y1Coefficient The y1 coefficient. + /// @param y2Coefficient The y2 coefficient. + /// @param yExponent The y exponent. + /// @return signedCoefficient The signed coefficient of the result. + /// @return exponent The exponent of the result. function unitLinearInterpolation( int256 x1Coefficient, int256 xCoefficient, diff --git a/src/lib/parse/LibParseDecimalFloat.sol b/src/lib/parse/LibParseDecimalFloat.sol index db6880d..0ce4b42 100644 --- a/src/lib/parse/LibParseDecimalFloat.sol +++ b/src/lib/parse/LibParseDecimalFloat.sol @@ -16,7 +16,21 @@ import {ParseEmptyDecimalString} from "rain.string/error/ErrParse.sol"; import {LibDecimalFloat, Float} from "../LibDecimalFloat.sol"; import {ParseDecimalFloatExcessCharacters} from "../../error/ErrParse.sol"; +/// @title LibParseDecimalFloat +/// @notice Library for parsing decimal floating point numbers from strings. +/// Not particularly gas efficient as it is intended for off-chain use cases. +/// Main use case is ensuring consistent behaviour across all offchain +/// implementations by standardizing in Solidity. library LibParseDecimalFloat { + /// @notice Parses a decimal float from a substring defined by [start, end). + /// @param start The starting index of the substring (inclusive). + /// @param end The ending index of the substring (exclusive). + /// @return errorSelector The error selector if an error occurred, otherwise + /// 0. + /// @return cursor The position in the string after parsing. + /// @return signedCoefficient The signed coefficient of the parsed decimal + /// float. + /// @return exponent The exponent of the parsed decimal float. function parseDecimalFloatInline(uint256 start, uint256 end) internal pure @@ -135,9 +149,23 @@ library LibParseDecimalFloat { exponent += eValue; } + + if (signedCoefficient == 0) { + // Normalize zero to have exponent zero. This ensures that parsed + // floats follow the behaviour of packed floats. + exponent = 0; + } } } + /// @notice Parses a decimal float from a string. This a high-level wrapper + /// around `parseDecimalFloatInline` that handles string memory layout and + /// returns a packed `Float` amenable to subsequent operations with + /// `LibDecimalFloat`. + /// @param str The string to parse. + /// @return errorSelector The error selector if an error occurred, otherwise + /// 0. + /// @return result The parsed `Float` if no error occurred, otherwise zero. function parseDecimalFloat(string memory str) internal pure returns (bytes4, Float) { uint256 start; uint256 end; @@ -150,7 +178,12 @@ library LibParseDecimalFloat { if (errorSelector == 0) { if (cursor == end) { // If we consumed the whole string, we can return the parsed value. - return (0, LibDecimalFloat.packLossless(signedCoefficient, exponent)); + (Float result, bool lossless) = LibDecimalFloat.packLossy(signedCoefficient, exponent); + if (!lossless) { + return (ParseDecimalPrecisionLoss.selector, Float.wrap(0)); + } else { + return (0, result); + } } else { // If we didn't consume the whole string, it is malformed. return (ParseDecimalFloatExcessCharacters.selector, Float.wrap(0)); diff --git a/src/lib/table/LibLogTable.sol b/src/lib/table/LibLogTable.sol index e47f99c..426d286 100644 --- a/src/lib/table/LibLogTable.sol +++ b/src/lib/table/LibLogTable.sol @@ -2,14 +2,20 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; +/// @dev Flag indicating that an entry in the log table points to the alternate +/// table. uint16 constant ALT_TABLE_FLAG = 0x8000; /// @dev The cardinality of the log mantissa for log table lookup. uint256 constant LOG_MANTISSA_IDX_CARDINALITY = 9000; + /// @dev The last index of the log mantissa for log table lookup. uint256 constant LOG_MANTISSA_LAST_INDEX = LOG_MANTISSA_IDX_CARDINALITY - 1; +/// @dev The cardinality of the antilog index for antilog table lookup. int256 constant ANTILOG_IDX_CARDINALITY = 10000; + +/// @dev The last index of the antilog index for antilog table lookup. int256 constant ANTILOG_IDX_LAST_INDEX = ANTILOG_IDX_CARDINALITY - 1; // The base size of the log tables is 1/10th the cardinality because the smallest @@ -17,6 +23,8 @@ int256 constant ANTILOG_IDX_LAST_INDEX = ANTILOG_IDX_CARDINALITY - 1; // corresponding value in the small table, it is just that the large table has // 2 byte values while the small table has 1 byte values. uint256 constant LOG_TABLE_SIZE_BASE = LOG_MANTISSA_IDX_CARDINALITY / 10; + +/// @dev The size in bytes of the full log table (both large and small). uint256 constant LOG_TABLE_SIZE_BYTES = LOG_TABLE_SIZE_BASE * 2; /// @dev As we deterministically deploy the log tables, we can run into @@ -25,6 +33,11 @@ bytes32 constant LOG_TABLE_DISAMBIGUATOR = keccak256("LOG_TABLE_DISAMBIGUATOR_1" /// @dev https://icap.org.pk/files/per/students/exam/notices/log-table.pdf library LibLogTable { + /// Encodes a log table into bytes for deployment. Used for AOT compilation + /// of the constants that are actually deployed on-chain. Compilation from + /// source and constants can be compared in CI. + /// @param table The log table to encode. + /// @return encoded The encoded log table. function toBytes(uint16[10][90] memory table) internal pure returns (bytes memory) { bytes memory encoded; uint256 tableSize = LOG_TABLE_SIZE_BYTES; @@ -54,6 +67,11 @@ library LibLogTable { return encoded; } + /// Encodes a log table into bytes for deployment. Used for AOT compilation + /// of the constants that are actually deployed on-chain. Compilation from + /// source and constants can be compared in CI. + /// @param table The log table to encode. + /// @return encoded The encoded log table. function toBytes(uint8[10][90] memory table) internal pure returns (bytes memory) { bytes memory encoded; uint256 tableSize = LOG_TABLE_SIZE_BASE; @@ -83,6 +101,11 @@ library LibLogTable { return encoded; } + /// Encodes a log table into bytes for deployment. Used for AOT compilation + /// of the constants that are actually deployed on-chain. Compilation from + /// source and constants can be compared in CI. + /// @param table The log table to encode. + /// @return encoded The encoded log table. function toBytes(uint8[10][100] memory table) internal pure returns (bytes memory) { bytes memory encoded; assembly ("memory-safe") { @@ -111,6 +134,11 @@ library LibLogTable { return encoded; } + /// Encodes a log table into bytes for deployment. Used for AOT compilation + /// of the constants that are actually deployed on-chain. Compilation from + /// source and constants can be compared in CI. + /// @param table The log table to encode. + /// @return encoded The encoded log table. function toBytes(uint8[10][10] memory table) internal pure returns (bytes memory) { bytes memory encoded; assembly ("memory-safe") { @@ -139,6 +167,11 @@ library LibLogTable { return encoded; } + /// Encodes a log table into bytes for deployment. Used for AOT compilation + /// of the constants that are actually deployed on-chain. Compilation from + /// source and constants can be compared in CI. + /// @param table The log table to encode. + /// @return encoded The encoded log table. function toBytes(uint16[10][100] memory table) internal pure returns (bytes memory) { bytes memory encoded; assembly ("memory-safe") { @@ -167,6 +200,9 @@ library LibLogTable { return encoded; } + /// The decimal log table used for logarithm calculations. AOT copmiled into + /// bytes that are deployed on-chain as data contracts. + /// @return The decimal log table. function logTableDec() internal pure returns (uint16[10][90] memory) { return [ [ @@ -372,6 +408,9 @@ library LibLogTable { ]; } + /// The small decimal log table used for logarithm calculations. AOT compiled + /// into bytes that are deployed on-chain as data contracts. + /// @return The small decimal log table. function logTableDecSmall() internal pure returns (uint8[10][90] memory) { return [ [0, 4, 9, 13, 17, 21, 26, 30, 34, 38], @@ -467,6 +506,9 @@ library LibLogTable { ]; } + /// The small decimal log table alternative used for logarithm calculations. + /// AOT compiled into bytes that are deployed on-chain as data contracts. + /// @return The small decimal log table alternative. function logTableDecSmallAlt() internal pure returns (uint8[10][10] memory) { return [ [0, 4, 8, 12, 16, 20, 24, 28, 32, 37], @@ -482,6 +524,9 @@ library LibLogTable { ]; } + /// The decimal anti log table used for logarithm calculations. AOT compiled + /// into bytes that are deployed on-chain as data contracts. + /// @return The decimal anti log table. function antiLogTableDec() internal pure returns (uint16[10][100] memory) { return [ [1000, 1002, 1005, 1007, 1009, 1012, 1014, 1016, 1019, 1021], @@ -587,6 +632,9 @@ library LibLogTable { ]; } + /// The small decimal anti log table used for logarithm calculations. AOT + /// compiled into bytes that are deployed on-chain as data contracts. + /// @return The small decimal anti log table. function antiLogTableDecSmall() internal pure returns (uint8[10][100] memory) { return [ [0, 0, 0, 1, 1, 1, 1, 2, 2, 2], diff --git a/test/src/concrete/DecimalFloat.format.t.sol b/test/src/concrete/DecimalFloat.format.t.sol index ff47c6e..7bfc955 100644 --- a/test/src/concrete/DecimalFloat.format.t.sol +++ b/test/src/concrete/DecimalFloat.format.t.sol @@ -11,7 +11,8 @@ contract DecimalFloatFormatTest is Test { using LibDecimalFloat for Float; function formatExternal(Float a, Float scientificMin, Float scientificMax) external pure returns (string memory) { - return LibFormatDecimalFloat.toDecimalString(a, a.lt(scientificMin) || a.gt(scientificMax)); + Float absA = a.abs(); + return LibFormatDecimalFloat.toDecimalString(a, absA.lt(scientificMin) || absA.gt(scientificMax)); } function testFormatDeployed(Float a, Float scientificMin, Float scientificMax) external { diff --git a/test/src/lib/LibDecimalFloat.ceil.t.sol b/test/src/lib/LibDecimalFloat.ceil.t.sol index ac6521d..4ebabbf 100644 --- a/test/src/lib/LibDecimalFloat.ceil.t.sol +++ b/test/src/lib/LibDecimalFloat.ceil.t.sol @@ -23,11 +23,9 @@ contract LibDecimalFloatCeilTest is Test { (int256 actualSignedCoefficient, int256 actualExponent) = LibDecimalFloat.ceil(LibDecimalFloat.packLossless(signedCoefficient, exponent)).unpack(); - if ( - !LibDecimalFloatImplementation.eq( + if (!LibDecimalFloatImplementation.eq( actualSignedCoefficient, actualExponent, expectedSignedCoefficient, expectedExponent - ) - ) { + )) { console2.log("signedCoefficient", signedCoefficient); console2.log("exponent", exponent); console2.log("expectedSignedCoefficient", expectedSignedCoefficient); @@ -87,17 +85,41 @@ contract LibDecimalFloatCeilTest is Test { /// Examples function testCeilExamples() external pure { checkCeil(123456789, 0, 123456789, 0); + checkCeil(-123456789, 0, -123456789, 0); + checkCeil(123456789, -1, 12345679000000000000000000000000000000000000000000000000000000000000, -60); + checkCeil(-123456789, -1, -123456780, -1); + checkCeil(123456789, -2, 12345680000000000000000000000000000000000000000000000000000000000000, -61); + checkCeil(-123456789, -2, -1234567e61, -61); + checkCeil(123456789, -3, 12345700000000000000000000000000000000000000000000000000000000000000, -62); + checkCeil(-123456789, -3, -123456e62, -62); + checkCeil(123456789, -4, 12346000000000000000000000000000000000000000000000000000000000000000, -63); + checkCeil(-123456789, -4, -12345e63, -63); + checkCeil(123456789, -5, 12350000000000000000000000000000000000000000000000000000000000000000, -64); + checkCeil(-123456789, -5, -1234e64, -64); + checkCeil(123456789, -6, 12400000000000000000000000000000000000000000000000000000000000000000, -65); + checkCeil(-123456789, -6, -123e65, -65); + checkCeil(123456789, -7, 13000000000000000000000000000000000000000000000000000000000000000000, -66); + checkCeil(-123456789, -7, -12e66, -66); + checkCeil(123456789, -8, 2000000000000000000000000000000000000000000000000000000000000000000, -66); + checkCeil(-123456789, -8, -1e67, -67); + checkCeil(123456789, -9, 1, 0); + checkCeil(-123456789, -9, 0, 0); + checkCeil(123456789, -10, 1, 0); + checkCeil(-123456789, -10, 0, 0); + checkCeil(123456789, -11, 1, 0); + checkCeil(-123456789, -11, 0, 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); diff --git a/test/src/lib/LibDecimalFloat.decimal.t.sol b/test/src/lib/LibDecimalFloat.decimal.t.sol index 6f511bc..47cb4a3 100644 --- a/test/src/lib/LibDecimalFloat.decimal.t.sol +++ b/test/src/lib/LibDecimalFloat.decimal.t.sol @@ -227,10 +227,7 @@ contract LibDecimalFloatDecimalTest is Test { /// If the final exponent is less than -77 then every value will be 0 when /// converted to fixed decimal. - function testToFixedDecimalLossyUnderflow(int256 signedCoefficient, int256 exponent, uint8 decimals) - external - pure - { + function testToFixedDecimalLossyUnderflow(int256 signedCoefficient, int256 exponent, uint8 decimals) external pure { signedCoefficient = bound(signedCoefficient, 1, type(int256).max); exponent = bound(exponent, type(int256).min, -78 - int256(uint256(decimals))); (uint256 value, bool lossless) = LibDecimalFloat.toFixedDecimalLossy(signedCoefficient, exponent, decimals); diff --git a/test/src/lib/LibDecimalFloat.floor.t.sol b/test/src/lib/LibDecimalFloat.floor.t.sol index 8519818..64bed88 100644 --- a/test/src/lib/LibDecimalFloat.floor.t.sol +++ b/test/src/lib/LibDecimalFloat.floor.t.sol @@ -3,8 +3,9 @@ pragma solidity =0.8.25; import {LibDecimalFloat, Float} from "src/lib/LibDecimalFloat.sol"; - +import {LibDecimalFloatImplementation} from "src/lib/implementation/LibDecimalFloatImplementation.sol"; import {Test} from "forge-std/Test.sol"; +import {console2} from "forge-std/console2.sol"; contract LibDecimalFloatFloorTest is Test { using LibDecimalFloat for Float; @@ -20,20 +21,35 @@ contract LibDecimalFloatFloorTest is Test { assertEq(exponent, expectedFracExponent); } + function checkFloorEq(int256 x, int256 exponent, int256 expectedFrac, int256 expectedFracExponent) internal pure { + Float a = LibDecimalFloat.packLossless(x, exponent); + (x, exponent) = a.floor().unpack(); + console2.log("x", x); + console2.log("exponent", exponent); + console2.log("expectedFrac", expectedFrac); + console2.log("expectedFracExponent", expectedFracExponent); + assertTrue((LibDecimalFloatImplementation.eq(x, exponent, expectedFrac, expectedFracExponent))); + } + /// Every non negative exponent is identity for floor. function testFloorNonNegative(int224 x, int256 exponent) external pure { exponent = bound(exponent, 0, type(int32).max); checkFloor(x, exponent, x, x == 0 ? int256(0) : exponent); } - /// If the exponent is less than -76 then the floor is 0. + /// If the exponent is less than -76 then the floor is 0 or -1. function testFloorLessThanMin(int224 x, int256 exponent) external pure { exponent = bound(exponent, type(int32).min, -77); - checkFloor(x, exponent, 0, 0); + if (x >= 0) { + checkFloor(x, exponent, 0, 0); + } else { + checkFloor(x, exponent, -1e67, -67); + } } /// For exponents [-76,-1] the floor is the / 1. - function testFloorInRange(int224 x, int256 exponent) external pure { + function testFloorInRangeNonNegative(int224 x, int256 exponent) external pure { + x = int224(bound(int256(x), 0, int256(type(int224).max))); exponent = bound(exponent, -76, -1); // exponent [-76, -1] // forge-lint: disable-next-line(unsafe-typecast) @@ -44,20 +60,62 @@ contract LibDecimalFloatFloorTest is Test { checkFloor(x, exponent, y, y == 0 ? int256(0) : exponent); } + /// For exponents [-76,-1] the floor is the / 1 - 1 if the float is negative. + function testFloorInRangeNegative(int224 x, int256 exponent) external pure { + x = int224(bound(int256(x), int256(type(int224).min), -1)); + exponent = bound(exponent, -76, -1); + // exponent [-76, -1] + // forge-lint: disable-next-line(unsafe-typecast) + int256 scale = int256(10 ** uint256(-exponent)); + // truncation is intentional here. + // forge-lint: disable-next-line(divide-before-multiply) + int256 y = (x / scale) * scale; + if (y != x) { + y -= scale; + } + checkFloorEq(x, exponent, y, y == 0 ? int256(0) : exponent); + } + /// Examples function testFloorExamples() external pure { checkFloor(123456789, 0, 123456789, 0); + checkFloor(-123456789, 0, -123456789, 0); + checkFloor(-1234567890, -1, -1234567890, -1); + checkFloor(123456789, -1, 123456780, -1); + checkFloor(-123456789, -1, -12345679e60, -60); + checkFloor(12345678900, -2, 12345678900, -2); + checkFloor(123456789, -2, 123456700, -2); + checkFloor(-123456789, -2, -1234568e61, -61); + checkFloor(123456789, -3, 123456000, -3); + checkFloor(-123456789, -3, -123457e62, -62); + checkFloor(123456789, -4, 123450000, -4); + checkFloor(-123456789, -4, -12346e63, -63); + checkFloor(123456789, -5, 123400000, -5); + checkFloor(-123456789, -5, -1235e64, -64); + checkFloor(123456789, -6, 123000000, -6); + checkFloor(-123456789, -6, -124e65, -65); + checkFloor(123456789, -7, 120000000, -7); + checkFloor(-123456789, -7, -13e66, -66); + checkFloor(123456789, -8, 100000000, -8); + checkFloor(-123456789, -8, -2e66, -66); + checkFloor(123456789, -9, 0, 0); + checkFloor(-123456789, -9, -1e67, -67); + checkFloor(123456789, -10, 0, 0); + checkFloor(-123456789, -10, -1e67, -67); + checkFloor(123456789, -11, 0, 0); + checkFloor(-123456789, -11, -1e67, -67); + checkFloor(type(int224).max, 0, type(int224).max, 0); checkFloor(type(int224).min, 0, type(int224).min, 0); diff --git a/test/src/lib/LibDecimalFloat.mul.t.sol b/test/src/lib/LibDecimalFloat.mul.t.sol index dcdeea9..57adbc8 100644 --- a/test/src/lib/LibDecimalFloat.mul.t.sol +++ b/test/src/lib/LibDecimalFloat.mul.t.sol @@ -29,8 +29,9 @@ contract LibDecimalFloatMulTest is Test { function testMulPacked(Float a, Float b) external { (int256 signedCoefficientA, int256 exponentA) = a.unpack(); (int256 signedCoefficientB, int256 exponentB) = b.unpack(); - try this.mulExternal(signedCoefficientA, exponentA, signedCoefficientB, exponentB) returns (Float floatExternal) - { + try this.mulExternal(signedCoefficientA, exponentA, signedCoefficientB, exponentB) returns ( + Float floatExternal + ) { (int256 signedCoefficient, int256 exponent) = floatExternal.unpack(); Float float = this.mulExternal(a, b); (int256 signedCoefficientUnpacked, int256 exponentUnpacked) = float.unpack(); diff --git a/test/src/lib/LibDecimalFloat.pow.t.sol b/test/src/lib/LibDecimalFloat.pow.t.sol index 3782f8d..a0d0bd6 100644 --- a/test/src/lib/LibDecimalFloat.pow.t.sol +++ b/test/src/lib/LibDecimalFloat.pow.t.sol @@ -175,6 +175,10 @@ contract LibDecimalFloatPowTest is LogTest { assertTrue(c.eq(LibDecimalFloat.FLOAT_ONE), "b is 0 so c should be 1"); } else if (!(c.isZero() && b.lt(LibDecimalFloat.FLOAT_ZERO))) { Float inv = b.inv(); + { + (, int256 exponentInv) = inv.unpack(); + vm.assume(exponentInv <= 8e8); + } // The round trip should not error so we do not try. Float roundTrip = this.powExternal(c, inv); if (!roundTrip.isZero()) { diff --git a/test/src/lib/deploy/LibDecimalFloatDeploy.t.sol b/test/src/lib/deploy/LibDecimalFloatDeploy.t.sol new file mode 100644 index 0000000..338bd1e --- /dev/null +++ b/test/src/lib/deploy/LibDecimalFloatDeploy.t.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {Test} from "forge-std/Test.sol"; + +import {LibDecimalFloatDeploy, DecimalFloat} from "src/lib/deploy/LibDecimalFloatDeploy.sol"; + +contract LibDecimalFloatDeployTest is Test { + function testDecimalFloatZoltu() external { + vm.createSelectFork(vm.envString("CI_FORK_ETH_RPC_URL")); + + DecimalFloat deployedZoltu = LibDecimalFloatDeploy.decimalFloatZoltu(); + assertTrue(address(deployedZoltu) != address(0)); + + DecimalFloat deployedDirect = new DecimalFloat(); + + assertEq(address(deployedZoltu).codehash, address(deployedDirect).codehash); + } + + function testDecimalFloatZoltuProd() external { + string[] memory forkRpcUrls = new string[](3); + forkRpcUrls[0] = "CI_FORK_FLARE_RPC_URL"; + forkRpcUrls[1] = "CI_FORK_BASE_RPC_URL"; + forkRpcUrls[2] = "CI_FORK_ARB_RPC_URL"; + + for (uint256 i = 0; i < forkRpcUrls.length; i++) { + vm.createSelectFork(vm.envString(forkRpcUrls[i])); + + assertEq( + LibDecimalFloatDeploy.DECIMAL_FLOAT_DATA_CONTRACT_HASH, + LibDecimalFloatDeploy.ZOLTU_DEPLOYED_DECIMAL_FLOAT_ADDRESS.codehash, + forkRpcUrls[i] + ); + } + } +} diff --git a/test/src/lib/format/LibFormatDecimalFloat.toDecimalString.t.sol b/test/src/lib/format/LibFormatDecimalFloat.toDecimalString.t.sol index 35eb732..2e6136a 100644 --- a/test/src/lib/format/LibFormatDecimalFloat.toDecimalString.t.sol +++ b/test/src/lib/format/LibFormatDecimalFloat.toDecimalString.t.sol @@ -18,8 +18,9 @@ contract LibFormatDecimalFloatToDecimalStringTest is Test { internal pure { - string memory actual = - LibFormatDecimalFloat.toDecimalString(LibDecimalFloat.packLossless(signedCoefficient, exponent), scientific); + string memory actual = LibFormatDecimalFloat.toDecimalString( + LibDecimalFloat.packLossless(signedCoefficient, exponent), scientific + ); assertEq(actual, expected, "Formatted value mismatch"); } diff --git a/test/src/lib/implementation/LibDecimalFloatImplementation.characteristicMantissa.t.sol b/test/src/lib/implementation/LibDecimalFloatImplementation.characteristicMantissa.t.sol deleted file mode 100644 index cce1476..0000000 --- a/test/src/lib/implementation/LibDecimalFloatImplementation.characteristicMantissa.t.sol +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: LicenseRef-DCL-1.0 -// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd -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"); - } - - 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); - - 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); - } - - function testCharacteristicMantissaNonNegExponent(int256 signedCoefficient, int256 exponent) public pure { - exponent = bound(exponent, 0, type(int256).max); - checkCharacteristicMantissa(signedCoefficient, exponent, signedCoefficient, 0); - } - - function testCharacteristicMantissaNegExponentLarge(int256 signedCoefficient, int256 exponent) public pure { - exponent = bound(exponent, type(int256).min, -77); - checkCharacteristicMantissa(signedCoefficient, exponent, 0, signedCoefficient); - } - - function testCharacteristicMantissaNegExponentSmall(int256 signedCoefficient) public pure { - for (int256 exponent = 1; exponent <= 76; exponent++) { - // exponent [1, 76] - // forge-lint: disable-next-line(unsafe-typecast) - int256 scale = int256(10 ** uint256(exponent)); - - int256 expectedMantissa = signedCoefficient % scale; - int256 expectedCharacteristic = signedCoefficient / scale * scale; - - checkCharacteristicMantissa(signedCoefficient, -exponent, expectedCharacteristic, expectedMantissa); - } - } -} diff --git a/test/src/lib/implementation/LibDecimalFloatImplementation.div.t.sol b/test/src/lib/implementation/LibDecimalFloatImplementation.div.t.sol index e406181..dfc5790 100644 --- a/test/src/lib/implementation/LibDecimalFloatImplementation.div.t.sol +++ b/test/src/lib/implementation/LibDecimalFloatImplementation.div.t.sol @@ -7,7 +7,8 @@ import { LibDecimalFloatImplementation, EXPONENT_MIN, EXPONENT_MAX, - DivisionByZero + DivisionByZero, + MaximizeOverflow } from "src/lib/implementation/LibDecimalFloatImplementation.sol"; import {THREES, ONES} from "../../../lib/LibCommonResults.sol"; @@ -44,6 +45,12 @@ contract LibDecimalFloatImplementationDivTest is Test { LibDecimalFloatImplementation.div(signedCoefficient, exponent, type(int256).max, type(int32).max); } + function testDivMinPositiveValueDenominatorRevert(int256 signedCoefficient, int256 exponent) external { + vm.assume(signedCoefficient != 0); + vm.expectRevert(abi.encodeWithSelector(MaximizeOverflow.selector, 1, type(int256).min)); + this.divExternal(signedCoefficient, exponent, 1, type(int256).min); + } + /// 1 / 3 gas by parts 10 function testDiv1Over3Gas10() external pure { (int256 c, int256 e) = LibDecimalFloatImplementation.div(1, 0, 3e37, -37); diff --git a/test/src/lib/implementation/LibDecimalFloatImplementation.eq.t.sol b/test/src/lib/implementation/LibDecimalFloatImplementation.eq.t.sol index 99c9404..761ec0e 100644 --- a/test/src/lib/implementation/LibDecimalFloatImplementation.eq.t.sol +++ b/test/src/lib/implementation/LibDecimalFloatImplementation.eq.t.sol @@ -57,8 +57,10 @@ contract LibDecimalFloatImplementationEqTest is Test { } } - /// xeX != yeY if x != y + /// xeX != yeY if x != y (assuming maximized representation) function testEqXNotY(int256 x, int256 exponentX, int256 y, int256 exponentY) external pure { + (x, exponentX,) = LibDecimalFloatImplementation.maximize(x, exponentX); + (y, exponentY,) = LibDecimalFloatImplementation.maximize(y, exponentY); vm.assume(x != y); bool eq = LibDecimalFloatImplementation.eq(x, exponentX, y, exponentY); assertTrue(!eq); diff --git a/test/src/lib/implementation/LibDecimalFloatImplementation.intFrac.t.sol b/test/src/lib/implementation/LibDecimalFloatImplementation.intFrac.t.sol new file mode 100644 index 0000000..6845fb3 --- /dev/null +++ b/test/src/lib/implementation/LibDecimalFloatImplementation.intFrac.t.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {Test} from "forge-std/Test.sol"; + +import {LibDecimalFloatImplementation} from "src/lib/implementation/LibDecimalFloatImplementation.sol"; + +contract LibDecimalFloatImplementationIntFracTest is Test { + function checkIntFrac(int256 signedCoefficient, int256 exponent, int256 expectedInteger, int256 expectedFraction) + internal + pure + { + (int256 actualInteger, int256 actualFraction) = + LibDecimalFloatImplementation.intFrac(signedCoefficient, exponent); + + assertEq(actualInteger, expectedInteger, "Integer mismatch"); + assertEq(actualFraction, expectedFraction, "Fraction mismatch"); + } + + function testIntFracExamples() public pure { + checkIntFrac(0, 0, 0, 0); + checkIntFrac(0, 1, 0, 0); + + checkIntFrac(5.4304950862250382e16, -16, 5e16, 4304950862250382); + checkIntFrac(-5.4304950862250382e16, -16, -5e16, -0.4304950862250382e16); + + checkIntFrac(5.4304950862250382e16, -76, 0, 5.4304950862250382e16); + checkIntFrac(-5.4304950862250382e16, -76, 0, -5.4304950862250382e16); + + // Exact multiple => zero fraction + checkIntFrac(5e16, -16, 5e16, 0); + checkIntFrac(-5e16, -16, -5e16, 0); + // Off-by-one around the multiple + checkIntFrac(5e16 + 1, -16, 5e16, 1); + checkIntFrac(-5e16 - 1, -16, -5e16, -1); + + // Boundary at exponent -76 (scale = 1e76) + checkIntFrac(1e76, -76, 1e76, 0); + checkIntFrac(1e76 + 1, -76, 1e76, 1); + checkIntFrac(-1e76, -76, -1e76, 0); + checkIntFrac(-1e76 - 1, -76, -1e76, -1); + + // Beyond boundary at exponent -77 (scale > int256.max): integer must be 0 + checkIntFrac(1, -77, 0, 1); + checkIntFrac(-1, -77, 0, -1); + } + + function testIntFracNonNegExponent(int256 signedCoefficient, int256 exponent) public pure { + exponent = bound(exponent, 0, type(int256).max); + checkIntFrac(signedCoefficient, exponent, signedCoefficient, 0); + } + + function testIntFracNegExponentLarge(int256 signedCoefficient, int256 exponent) public pure { + exponent = bound(exponent, type(int256).min, -77); + checkIntFrac(signedCoefficient, exponent, 0, signedCoefficient); + } + + function testIntFracNegExponentSmall(int256 signedCoefficient) public pure { + for (int256 exponent = 1; exponent <= 76; exponent++) { + // exponent [1, 76] + // forge-lint: disable-next-line(unsafe-typecast) + int256 scale = int256(10 ** uint256(exponent)); + + int256 expectedFraction = signedCoefficient % scale; + int256 expectedInteger = signedCoefficient / scale * scale; + + checkIntFrac(signedCoefficient, -exponent, expectedInteger, expectedFraction); + } + } +} diff --git a/test/src/lib/implementation/LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy.t.sol b/test/src/lib/implementation/LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy.t.sol index 8a9a328..c6dbccf 100644 --- a/test/src/lib/implementation/LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy.t.sol +++ b/test/src/lib/implementation/LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy.t.sol @@ -13,10 +13,12 @@ contract LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest is Test { b = bound(b, 0, uint256(type(int256).max)); c = bound(c, 0, uint256(type(int256).max)); - (int256 actualSignedCoefficient, int256 actualExponent) = - // a and b are both bound to the int256 range. - // forge-lint: disable-next-line(unsafe-typecast) - LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(int256(a), int256(b), c, exponent); + ( + int256 actualSignedCoefficient, + int256 actualExponent + // a and b are both bound to the int256 range. + // forge-lint: disable-next-line(unsafe-typecast) + ) = LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(int256(a), int256(b), c, exponent); // c is range bound so won't truncate when cast. // forge-lint: disable-next-line(unsafe-typecast) @@ -37,10 +39,12 @@ contract LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest is Test { c = bound(c, uint256(type(int256).max) + 1, type(uint256).max); vm.assume(exponent != type(int256).max); // Prevent overflow in exponent. - (int256 actualSignedCoefficient, int256 actualExponent) = - // a and b are both bound to the int256 range. - // forge-lint: disable-next-line(unsafe-typecast) - LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(int256(a), int256(b), c, exponent); + ( + int256 actualSignedCoefficient, + int256 actualExponent + // a and b are both bound to the int256 range. + // forge-lint: disable-next-line(unsafe-typecast) + ) = LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(int256(a), int256(b), c, exponent); // Expect the result to be positive. // c is divided by 10 before being cast to int256 so won't truncate. // forge-lint: disable-next-line(unsafe-typecast) @@ -56,10 +60,12 @@ contract LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest is Test { b = bound(b, 1, uint256(type(int256).max)); c = bound(c, 0, uint256(type(int256).max)); - (int256 actualSignedCoefficient, int256 actualExponent) = - // a and b are both bound to the int256 range. - // forge-lint: disable-next-line(unsafe-typecast) - LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), -int256(b), c, exponent); + ( + int256 actualSignedCoefficient, + int256 actualExponent + // a and b are both bound to the int256 range. + // forge-lint: disable-next-line(unsafe-typecast) + ) = LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), -int256(b), c, exponent); // c is range bound so won't truncate when cast. // forge-lint: disable-next-line(unsafe-typecast) @@ -80,10 +86,12 @@ contract LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest is Test { c = bound(c, uint256(type(int256).max) + 1, type(uint256).max); vm.assume(exponent != type(int256).max); // Prevent overflow in exponent. - (int256 actualSignedCoefficient, int256 actualExponent) = - // a and b are both bound to the int256 range. - // forge-lint: disable-next-line(unsafe-typecast) - LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), -int256(b), c, exponent); + ( + int256 actualSignedCoefficient, + int256 actualExponent + // a and b are both bound to the int256 range. + // forge-lint: disable-next-line(unsafe-typecast) + ) = LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), -int256(b), c, exponent); // Expect the result to be positive. // c is divided by 10 before being cast to int256 so won't truncate. @@ -101,10 +109,12 @@ contract LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest is Test { b = bound(b, 0, uint256(type(int256).max)); c = bound(c, 0, uint256(type(int256).max)); - (int256 actualSignedCoefficient, int256 actualExponent) = - // a and b are both bound to the int256 range. - // forge-lint: disable-next-line(unsafe-typecast) - LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), int256(b), c, exponent); + ( + int256 actualSignedCoefficient, + int256 actualExponent + // a and b are both bound to the int256 range. + // forge-lint: disable-next-line(unsafe-typecast) + ) = LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), int256(b), c, exponent); // Expect the result to be negative. // c is range bound so won't truncate when cast. @@ -123,12 +133,14 @@ contract LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest is Test { c = bound(c, uint256(type(int256).max) + 2, type(uint256).max); vm.assume(exponent != type(int256).max); // Prevent overflow in exponent. - (int256 actualSignedCoefficient, int256 actualExponent) = - // a is in range so won't truncate when cast. - // b is capped at type(int256).max so won't truncate when cast and can - // be negated directly. - // forge-lint: disable-next-line(unsafe-typecast) - LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(int256(a), -int256(b), c, exponent); + ( + int256 actualSignedCoefficient, + int256 actualExponent + // a is in range so won't truncate when cast. + // b is capped at type(int256).max so won't truncate when cast and can + // be negated directly. + // forge-lint: disable-next-line(unsafe-typecast) + ) = LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(int256(a), -int256(b), c, exponent); // Expect the result to be negative. // c is divided by 10 before being cast to int256 so won't truncate. @@ -150,10 +162,12 @@ contract LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest is Test { c = bound(c, uint256(type(int256).max) + 2, type(uint256).max); vm.assume(exponent != type(int256).max); // Prevent overflow in exponent. - (int256 actualSignedCoefficient, int256 actualExponent) = - // a and b are both bound to the int256 range. - // forge-lint: disable-next-line(unsafe-typecast) - LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), int256(b), c, exponent); + ( + int256 actualSignedCoefficient, + int256 actualExponent + // a and b are both bound to the int256 range. + // forge-lint: disable-next-line(unsafe-typecast) + ) = LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(-int256(a), int256(b), c, exponent); // Expect the result to be negative. // c is divided by 10 before being cast to int256 so won't truncate. @@ -172,9 +186,11 @@ contract LibDecimalFloatImplementationUnabsUnsignedMulOrDivLossyTest is Test { uint256 c = uint256(type(int256).max) + 1; // b is capped at type(int256).max so won't truncate when cast and can // be negated directly. - (int256 actualSignedCoefficient, int256 actualExponent) = - // forge-lint: disable-next-line(unsafe-typecast) - LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(int256(a), -int256(b), c, exponent); + ( + int256 actualSignedCoefficient, + int256 actualExponent + // forge-lint: disable-next-line(unsafe-typecast) + ) = LibDecimalFloatImplementation.unabsUnsignedMulOrDivLossy(int256(a), -int256(b), c, exponent); // Expect the result to be negative. int256 expectedSignedCoefficient = type(int256).min; int256 expectedExponent = exponent; diff --git a/test/src/lib/implementation/LibDecimalFloatImplementation.withTargetExponent.t.sol b/test/src/lib/implementation/LibDecimalFloatImplementation.withTargetExponent.t.sol index 1d8aabd..0a0df24 100644 --- a/test/src/lib/implementation/LibDecimalFloatImplementation.withTargetExponent.t.sol +++ b/test/src/lib/implementation/LibDecimalFloatImplementation.withTargetExponent.t.sol @@ -98,8 +98,9 @@ contract LibDecimalFloatImplementationWithTargetExponentTest is Test { int256 targetExponent, int256 expectedSignedCoefficient ) internal pure { - int256 actualSignedCoefficient = - LibDecimalFloatImplementation.withTargetExponent(signedCoefficient, exponent, targetExponent); + int256 actualSignedCoefficient = LibDecimalFloatImplementation.withTargetExponent( + signedCoefficient, exponent, targetExponent + ); assertEq(actualSignedCoefficient, expectedSignedCoefficient, "signedCoefficient"); } diff --git a/test/src/lib/parse/LibParseDecimalFloat.t.sol b/test/src/lib/parse/LibParseDecimalFloat.t.sol index 28e1f2d..f165c60 100644 --- a/test/src/lib/parse/LibParseDecimalFloat.t.sol +++ b/test/src/lib/parse/LibParseDecimalFloat.t.sol @@ -14,6 +14,7 @@ import { MalformedDecimalPoint, ParseDecimalFloatExcessCharacters } from "src/error/ErrParse.sol"; +import {ExponentOverflow, CoefficientOverflow} from "src/error/ErrDecimalFloat.sol"; import {Float, LibDecimalFloat} from "src/lib/LibDecimalFloat.sol"; contract LibParseDecimalFloatTest is Test { @@ -52,6 +53,18 @@ contract LibParseDecimalFloatTest is Test { errorSelector = ParseDecimalFloatExcessCharacters.selector; signedCoefficient = 0; exponent = 0; + // forge-lint: disable-next-line(unsafe-typecast) + } else if (exponent != int32(exponent) && exponent > 0 && signedCoefficient == int224(signedCoefficient)) { + vm.expectRevert(abi.encodeWithSelector(ExponentOverflow.selector, signedCoefficient, exponent)); + signedCoefficient = 0; + exponent = 0; + } else { + (, bool lossless) = LibDecimalFloat.packLossy(signedCoefficient, exponent); + if (!lossless) { + errorSelector = ParseDecimalPrecisionLoss.selector; + signedCoefficient = 0; + exponent = 0; + } } (bytes4 errorSelectorPacked, Float float) = this.parseDecimalFloatExternal(data); @@ -204,10 +217,10 @@ contract LibParseDecimalFloatTest is Test { checkParseDecimalFloat("0e0", 0, 0, 3); // A capital E. checkParseDecimalFloat("0E0", 0, 0, 3); - checkParseDecimalFloat("0e1", 0, 1, 3); - checkParseDecimalFloat("0e2", 0, 2, 3); - checkParseDecimalFloat("0e-1", 0, -1, 4); - checkParseDecimalFloat("0e-2", 0, -2, 4); + checkParseDecimalFloat("0e1", 0, 0, 3); + checkParseDecimalFloat("0e2", 0, 0, 3); + checkParseDecimalFloat("0e-1", 0, 0, 4); + checkParseDecimalFloat("0e-2", 0, 0, 4); checkParseDecimalFloat("1e1", 1, 1, 3); checkParseDecimalFloat("1e2", 1, 2, 3); @@ -275,7 +288,7 @@ contract LibParseDecimalFloatTest is Test { ); checkParseDecimalFloat("0.0e0", 0, 0, 5); - checkParseDecimalFloat("0.0e1", 0, 1, 5); + checkParseDecimalFloat("0.0e1", 0, 0, 5); checkParseDecimalFloat("1.1e1", 11, 0, 5); checkParseDecimalFloat("1.1e-1", 11, -2, 6); @@ -289,7 +302,7 @@ contract LibParseDecimalFloatTest is Test { function testParseLiteralDecimalFloatUnrelated() external pure { checkParseDecimalFloat("0.0hello", 0, 0, 3); checkParseDecimalFloat("0.0e0hello", 0, 0, 5); - checkParseDecimalFloat("0.0e1hello", 0, 1, 5); + checkParseDecimalFloat("0.0e1hello", 0, 0, 5); checkParseDecimalFloat("1.1e1hello", 11, 0, 5); checkParseDecimalFloat("1.1e-1hello", 11, -2, 6); checkParseDecimalFloat("-1.1e-1hello", -11, -2, 7);