Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 80 additions & 40 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,72 +1,112 @@
LibDecimalFloatAbsTest:testAbsMinValue(int256) (runs: 2054, μ: 4419, ~: 4419)
LibDecimalFloatAbsTest:testAbsNegative(int256,int256) (runs: 2055, μ: 9920, ~: 10164)
LibDecimalFloatAbsTest:testAbsNonNegative(int256,int256) (runs: 2055, μ: 9033, ~: 8691)
LibDecimalFloatCompareTest:testCompareOne() (gas: 5610)
LibDecimalFloatCompareTest:testCompareOnePointSix() (gas: 4430)
LibDecimalFloatCompareTest:testCompareTen() (gas: 4939)
LibDecimalFloatAbsTest:testAbsMinValue(int256) (runs: 5108, μ: 4419, ~: 4419)
LibDecimalFloatAbsTest:testAbsNegative(int256,int256) (runs: 5109, μ: 9914, ~: 10164)
LibDecimalFloatAbsTest:testAbsNonNegative(int256,int256) (runs: 5109, μ: 9040, ~: 8691)
LibDecimalFloatDecimalAddTest:testAdd123456789987654321() (gas: 6203)
LibDecimalFloatDecimalAddTest:testAdd123456789e9987654321() (gas: 6255)
LibDecimalFloatDecimalAddTest:testAddNeverRevert(int256,int256,int256,int256) (runs: 2055, μ: 14171, ~: 14075)
LibDecimalFloatDecimalAddTest:testAddNeverRevert(int256,int256,int256,int256) (runs: 5109, μ: 14149, ~: 14075)
LibDecimalFloatDecimalAddTest:testAddOneOneNotNormalized() (gas: 5818)
LibDecimalFloatDecimalAddTest:testAddOneOnePreNormalized() (gas: 4250)
LibDecimalFloatDecimalAddTest:testAddOneZero() (gas: 3688)
LibDecimalFloatDecimalAddTest:testAddSameExponentSameCoefficient(int256,int256) (runs: 2055, μ: 6413, ~: 6424)
LibDecimalFloatDecimalAddTest:testAddSameExponentSameCoefficient(int256,int256) (runs: 5109, μ: 6415, ~: 6427)
LibDecimalFloatDecimalAddTest:testAddZero() (gas: 3664)
LibDecimalFloatDecimalAddTest:testAddZeroAnyExponent(int128) (runs: 2055, μ: 9311, ~: 9245)
LibDecimalFloatDecimalAddTest:testAddZeroAnyExponent(int128) (runs: 5109, μ: 9310, ~: 9245)
LibDecimalFloatDecimalAddTest:testAddZeroOne() (gas: 3686)
LibDecimalFloatDecimalAddTest:testAddZeroToAnyNonZero(int256,int256,int256) (runs: 2054, μ: 14297, ~: 14176)
LibDecimalFloatDecimalAddTest:testAddZeroToAnyNonZero(int256,int256,int256) (runs: 5108, μ: 14299, ~: 14243)
LibDecimalFloatDecimalAddTest:testAddingSmallToLargeReturnsLargeExamples() (gas: 19289)
LibDecimalFloatDecimalAddTest:testAddingSmallToLargeReturnsLargeFuzz(int256,int256,int256,int256) (runs: 2050, μ: 18699, ~: 18758)
LibDecimalFloatDecimalAddTest:testAddingSmallToLargeReturnsLargeFuzz(int256,int256,int256,int256) (runs: 5100, μ: 18700, ~: 18773)
LibDecimalFloatDecimalAddTest:testGasAddOne() (gas: 944)
LibDecimalFloatDecimalAddTest:testGasAddZero() (gas: 382)
LibDecimalFloatDecimalTest:testFixedDecimalRoundTripLossless(uint256,uint8) (runs: 2055, μ: 10145, ~: 10196)
LibDecimalFloatDecimalTest:testFixedDecimalRoundTripLossless(uint256,uint8) (runs: 5109, μ: 10148, ~: 10196)
LibDecimalFloatDecimalTest:testFromFixedDecimalLossyComplicated() (gas: 1022048)
LibDecimalFloatDecimalTest:testFromFixedDecimalLossyNormalizedMax() (gas: 760206)
LibDecimalFloatDecimalTest:testFromFixedDecimalLossyNormalizedMaxPlusOne() (gas: 866032)
LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOne() (gas: 975616)
LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOneMillion() (gas: 952412)
LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOverflow() (gas: 838681)
LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateOne(uint256,uint8) (runs: 2055, μ: 9551, ~: 7195)
LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateZero(uint256,uint8) (runs: 2055, μ: 8542, ~: 7207)
LibDecimalFloatDecimalTest:testToFixedDecimalLosslessScaleUp(int256,int256,uint8) (runs: 2052, μ: 16001, ~: 16228)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyExponentOverflow(int256,int256,uint8) (runs: 2055, μ: 14938, ~: 14718)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyIdentity(int256,uint8) (runs: 2055, μ: 10109, ~: 9778)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyNegative(int256,int256,uint8) (runs: 2055, μ: 9916, ~: 10161)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyScaleUpOverflow(int256,int256,uint8) (runs: 2051, μ: 13915, ~: 14172)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncate(int256,int256,uint8) (runs: 2055, μ: 14458, ~: 14188)
LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateOne(uint256,uint8) (runs: 5109, μ: 9541, ~: 7195)
LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateZero(uint256,uint8) (runs: 5109, μ: 8537, ~: 7207)
LibDecimalFloatDecimalTest:testToFixedDecimalLosslessScaleUp(int256,int256,uint8) (runs: 5103, μ: 15985, ~: 15974)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyExponentOverflow(int256,int256,uint8) (runs: 5109, μ: 14953, ~: 14718)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyIdentity(int256,uint8) (runs: 5109, μ: 10117, ~: 9778)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyNegative(int256,int256,uint8) (runs: 5109, μ: 9905, ~: 10161)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyScaleUpOverflow(int256,int256,uint8) (runs: 5102, μ: 13918, ~: 14172)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncate(int256,int256,uint8) (runs: 5109, μ: 14472, ~: 14190)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncateLossless() (gas: 14500)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyUnderflow(int256,int256,uint8) (runs: 2055, μ: 13700, ~: 13580)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyZero(int256,uint8) (runs: 2055, μ: 4575, ~: 4575)
LibDecimalFloatDivideTest:testDivide1Over3() (gas: 6240)
LibDecimalFloatDivideTest:testDivide1Over3Gas0() (gas: 679)
LibDecimalFloatDivideTest:testDivide1Over3Gas10() (gas: 6248)
LibDecimalFloatDivideTest:testDivide1Over9Over1Over3() (gas: 9610)
LibDecimalFloatDivideTest:testDivide1e18Over3() (gas: 5249)
LibDecimalFloatDivideTest:testDivideNegative1Over3() (gas: 6324)
LibDecimalFloatDivideTest:testDivideOOMs5and2() (gas: 3928)
LibDecimalFloatDivideTest:testDivideOOMsOverTen() (gas: 4952)
LibDecimalFloatDivideTest:testDivideTenOverOOMs() (gas: 4862)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyUnderflow(int256,int256,uint8) (runs: 5109, μ: 13713, ~: 13580)
LibDecimalFloatDecimalTest:testToFixedDecimalLossyZero(int256,uint8) (runs: 5109, μ: 4575, ~: 4575)
LibDecimalFloatDivideTest:testDivide1Over3() (gas: 6420)
LibDecimalFloatDivideTest:testDivide1Over3Gas0() (gas: 761)
LibDecimalFloatDivideTest:testDivide1Over3Gas10() (gas: 7068)
LibDecimalFloatDivideTest:testDivide1Over9Over1Over3() (gas: 9856)
LibDecimalFloatDivideTest:testDivide1e18Over3() (gas: 6148)
LibDecimalFloatDivideTest:testDivideNegative1Over3() (gas: 6490)
LibDecimalFloatDivideTest:testDivideOOMs5and2() (gas: 4827)
LibDecimalFloatDivideTest:testDivideOOMsOverTen() (gas: 5873)
LibDecimalFloatDivideTest:testDivideTenOverOOMs() (gas: 5738)
LibDecimalFloatDivideTest:testUnnormalizedThreesDivision0(int256,int256) (runs: 113, μ: 23628114, ~: 23628366)
LibDecimalFloatEqTest:testEqGasAZero() (gas: 430)
LibDecimalFloatEqTest:testEqGasBZero() (gas: 473)
LibDecimalFloatEqTest:testEqGasBothZero() (gas: 450)
LibDecimalFloatEqTest:testEqGasDifferentSigns() (gas: 482)
LibDecimalFloatEqTest:testEqGasExponentDiffOverflow() (gas: 578)
LibDecimalFloatEqTest:testEqNotReverts(int256,int256,int256,int256) (runs: 5109, μ: 653, ~: 679)
LibDecimalFloatEqTest:testEqOneEAny(int256,int256) (runs: 5109, μ: 3416, ~: 3416)
LibDecimalFloatEqTest:testEqReference(int256,int256,int256,int256) (runs: 5109, μ: 9883, ~: 11437)
LibDecimalFloatEqTest:testEqX(int256) (runs: 5109, μ: 3392, ~: 3392)
LibDecimalFloatEqTest:testEqXEAnyVsXEAny(int256,int256,int256) (runs: 5107, μ: 4716, ~: 4714)
LibDecimalFloatEqTest:testEqXEqY(int256,int256,int256,int256) (runs: 5109, μ: 732, ~: 753)
LibDecimalFloatEqTest:testEqXNotY(int256,int256,int256,int256) (runs: 5107, μ: 3927, ~: 3953)
LibDecimalFloatEqTest:testEqXNotYExponents(int256,int256,int256,int256) (runs: 5109, μ: 4241, ~: 4321)
LibDecimalFloatEqTest:testEqZero(int256,int256) (runs: 5109, μ: 3440, ~: 3440)
LibDecimalFloatGtTest:testGtGasAZero() (gas: 429)
LibDecimalFloatGtTest:testGtGasBZero() (gas: 428)
LibDecimalFloatGtTest:testGtGasBothZero() (gas: 452)
LibDecimalFloatGtTest:testGtGasDifferentSigns() (gas: 430)
LibDecimalFloatGtTest:testGtGasExponentDiffOverflow() (gas: 578)
LibDecimalFloatGtTest:testGtOneEAny(int256,int256) (runs: 5109, μ: 3443, ~: 3443)
LibDecimalFloatGtTest:testGtReference(int256,int256,int256,int256) (runs: 5109, μ: 9876, ~: 11407)
LibDecimalFloatGtTest:testGtX(int256) (runs: 5109, μ: 3417, ~: 3417)
LibDecimalFloatGtTest:testGtXEAnyVsXEAny(int256,int256,int256) (runs: 5109, μ: 9742, ~: 9530)
LibDecimalFloatGtTest:testGtXEAnyVsXEAnyNegative(int256,int256,int256) (runs: 5109, μ: 10324, ~: 10570)
LibDecimalFloatGtTest:testGtXNotY(int256,int256,int256,int256) (runs: 5109, μ: 4207, ~: 4286)
LibDecimalFloatGtTest:testGtXPositiveYNegative(int256,int256,int256,int256) (runs: 5109, μ: 12894, ~: 12801)
LibDecimalFloatGtTest:testGtXPositiveYZero(int256,int256,int256) (runs: 5109, μ: 9465, ~: 9255)
LibDecimalFloatGtTest:testGtZero(int256,int256) (runs: 5109, μ: 3465, ~: 3465)
LibDecimalFloatInvTest:testInvGas0() (gas: 734)
LibDecimalFloatInvTest:testInvReference(int256,int256) (runs: 2054, μ: 13005, ~: 13131)
LibDecimalFloatInvTest:testInvReference(int256,int256) (runs: 5107, μ: 13016, ~: 13131)
LibDecimalFloatInvTest:testInvSlowGas0() (gas: 755)
LibDecimalFloatLog10Test:testExactLogs() (gas: 19667)
LibDecimalFloatLtTest:testLtGasAZero() (gas: 450)
LibDecimalFloatLtTest:testLtGasBZero() (gas: 472)
LibDecimalFloatLtTest:testLtGasBothZero() (gas: 451)
LibDecimalFloatLtTest:testLtGasDifferentSigns() (gas: 473)
LibDecimalFloatLtTest:testLtGasExponentDiffOverflow() (gas: 535)
LibDecimalFloatLtTest:testLtNegativeVsPositive(int256,int256,int256,int256) (runs: 5109, μ: 12879, ~: 12780)
LibDecimalFloatLtTest:testLtNegativeVsZero(int256,int256,int256) (runs: 5109, μ: 10028, ~: 10276)
LibDecimalFloatLtTest:testLtOneEAny(int256,int256) (runs: 5109, μ: 3465, ~: 3465)
LibDecimalFloatLtTest:testLtReference(int256,int256,int256,int256) (runs: 5109, μ: 9901, ~: 11454)
LibDecimalFloatLtTest:testLtVsEqualVsGt(int256,int256,int256,int256) (runs: 5109, μ: 4258, ~: 4332)
LibDecimalFloatLtTest:testLtX(int256) (runs: 5109, μ: 3438, ~: 3438)
LibDecimalFloatLtTest:testLtXEAnyVsXEAny(int256,int256,int256) (runs: 5109, μ: 9764, ~: 9552)
LibDecimalFloatLtTest:testLtXEAnyVsXEAnyNegative(int256,int256,int256) (runs: 5109, μ: 10303, ~: 10548)
LibDecimalFloatLtTest:testLtZero(int256,int256) (runs: 5109, μ: 3442, ~: 3442)
LibDecimalFloatMixedTest:testDivide1Over3() (gas: 7213)
LibDecimalFloatMultiplyTest:testMultiply123456789987654321() (gas: 3720)
LibDecimalFloatMultiplyTest:testMultiply123456789987654321WithExponents(int128,int128) (runs: 2055, μ: 13188, ~: 13269)
LibDecimalFloatMultiplyTest:testMultiply123456789987654321WithExponents(int128,int128) (runs: 5109, μ: 13184, ~: 13269)
LibDecimalFloatMultiplyTest:testMultiply1e181e19() (gas: 3721)
LibDecimalFloatMultiplyTest:testMultiplyGasOne() (gas: 382)
LibDecimalFloatMultiplyTest:testMultiplyGasZero() (gas: 348)
LibDecimalFloatMultiplyTest:testMultiplyNotRevertAnyExpectation(int256,int256,int256,int256) (runs: 2055, μ: 13892, ~: 13096)
LibDecimalFloatMultiplyTest:testMultiplyNotRevertAnyExpectation(int256,int256,int256,int256) (runs: 5109, μ: 13910, ~: 13097)
LibDecimalFloatMultiplyTest:testMultiplyOneOne() (gas: 3697)
LibDecimalFloatMultiplyTest:testMultiplyOneZero() (gas: 3663)
LibDecimalFloatMultiplyTest:testMultiplyZero0Exponent() (gas: 3619)
LibDecimalFloatMultiplyTest:testMultiplyZeroAnyExponent(int64,int64) (runs: 2055, μ: 3907, ~: 3907)
LibDecimalFloatMultiplyTest:testMultiplyZeroAnyExponent(int64,int64) (runs: 5109, μ: 3907, ~: 3907)
LibDecimalFloatMultiplyTest:testMultiplyZeroOne() (gas: 3620)
LibDecimalFloatPackTest:testNormalizedRoundTrip(int256,int256) (runs: 2055, μ: 11156, ~: 11057)
LibDecimalFloatPackTest:testPartsRoundTrip(int128,int128) (runs: 2055, μ: 4718, ~: 4718)
LibDecimalFloatSubTest:testMinusIsSubZero(int256,int256,int256) (runs: 2055, μ: 13219, ~: 13282)
LibDecimalFloatSubTest:testSubIsAdd(int256,int256,int256,int256) (runs: 2055, μ: 17626, ~: 17848)
LibDecimalFloatSubTest:testSubMinSignedValue(int256,int256,int256) (runs: 2055, μ: 17359, ~: 17268)
LibDecimalFloatPackTest:testNormalizedRoundTrip(int256,int256) (runs: 5109, μ: 11154, ~: 11057)
LibDecimalFloatPackTest:testPartsRoundTrip(int128,int128) (runs: 5109, μ: 4718, ~: 4718)
LibDecimalFloatSubTest:testMinusIsSubZero(int256,int256,int256) (runs: 5109, μ: 13217, ~: 13268)
LibDecimalFloatSubTest:testSubIsAdd(int256,int256,int256,int256) (runs: 5108, μ: 17589, ~: 17843)
LibDecimalFloatSubTest:testSubMinSignedValue(int256,int256,int256) (runs: 5109, μ: 17350, ~: 17236)
LibLogTableBytesTest:testToBytesAntiLogTableDec() (gas: 158027)
LibLogTableBytesTest:testToBytesAntiLogTableDecSmall() (gas: 160620)
LibLogTableBytesTest:testToBytesLogTableDec() (gas: 141631)
Expand Down
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ remappings = [
]

[fuzz]
runs = 2048
runs = 5096
110 changes: 67 additions & 43 deletions src/lib/LibDecimalFloat.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,6 @@ import {
EXPONENT_STEP_SIZE
} from "./implementation/LibDecimalFloatImplementation.sol";

/// @dev Returned by `compare` when the first operand is less than the second.
int256 constant COMPARE_LESS_THAN = -1;
/// @dev Returned by `compare` when the operands are equal.
int256 constant COMPARE_EQUAL = 0;
/// @dev Returned by `compare` when the first operand is greater than the second.
int256 constant COMPARE_GREATER_THAN = 1;

uint256 constant ADD_MAX_EXPONENT_DIFF = 37;

/// @dev When normalizing a number, how far we "leap" when very far from
Expand Down Expand Up @@ -575,45 +568,76 @@ library LibDecimalFloat {
return (signedCoefficient, exponent);
}

/// https://speleotrove.com/decimal/daops.html#refnumco
/// > compare takes two operands and compares their values numerically. If
/// > either operand is a special value then the general rules apply. No
/// > flags are set unless an operand is a signaling NaN.
/// >
/// > Otherwise, the operands are compared as follows.
/// >
/// > If the signs of the operands differ, a value representing each operand
/// > (’-1’ if the operand is less than zero, ’0’ if the operand is zero or
/// > negative zero, or ’1’ if the operand is greater than zero) is used in
/// > place of that operand for the comparison instead of the actual operand.
/// >
/// > The comparison is then effected by subtracting the second operand from
/// > the first and then returning a value according to the result of the
/// > subtraction: ’-1’ if the result is less than zero, ’0’ if the result is
/// > zero or negative zero, or ’1’ if the result is greater than zero.
/// >
/// > An implementation may use this operation ‘under the covers’ to
/// > implement a closed set of comparison operations
/// > (greater than, equal,etc.) if desired. It need not, in this case,
/// > expose the compare operation itself.
function compare(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB)
/// Numeric equality for floats.
/// Two floats are equal if their numeric value is equal.
/// For example, 1e2, 10e1, and 100e0 are all equal. Also implies that 0eX
/// and 0eY are equal for all X and Y.
/// Any representable value can be equality checked without precision loss,
/// e.g. no normalization is done internally.
/// @param signedCoefficientA The signed coefficient of the first floating
/// point number.
/// @param exponentA The exponent of the first floating point number.
/// @param signedCoefficientB The signed coefficient of the second floating
/// point number.
/// @param exponentB The exponent of the second floating point number.
/// @return `true` if the two floats are equal, `false` otherwise.
function eq(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB)
internal
pure
returns (int256)
returns (bool)
{
// We don't support negative zero.
(signedCoefficientB, exponentB) = minus(signedCoefficientB, exponentB);
// We want the un-normalized result so that rounding doesn't affect the
// comparison.
(int256 signedCoefficient,) = add(signedCoefficientA, exponentA, signedCoefficientB, exponentB);

if (signedCoefficient == 0) {
return COMPARE_EQUAL;
} else if (signedCoefficient < 0) {
return COMPARE_LESS_THAN;
} else {
return COMPARE_GREATER_THAN;
}
(signedCoefficientA, signedCoefficientB) =
LibDecimalFloatImplementation.compareRescale(signedCoefficientA, exponentA, signedCoefficientB, exponentB);

return signedCoefficientA == signedCoefficientB;
}

/// Numeric less than for floats.
/// A float is less than another if its numeric value is less than the other.
/// For example, 1e2 is less than 1e3, and 1e2 is less than 2e2.
/// Any representable value can be compared without precision loss, e.g. no
/// normalization is done internally.
/// @param signedCoefficientA The signed coefficient of the first floating
/// point number.
/// @param exponentA The exponent of the first floating point number.
/// @param signedCoefficientB The signed coefficient of the second floating
/// point number.
/// @param exponentB The exponent of the second floating point number.
/// @return `true` if the first float is less than the second, `false`
/// otherwise.
function lt(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB)
internal
pure
returns (bool)
{
(signedCoefficientA, signedCoefficientB) =
LibDecimalFloatImplementation.compareRescale(signedCoefficientA, exponentA, signedCoefficientB, exponentB);

return signedCoefficientA < signedCoefficientB;
}

/// Numeric greater than for floats.
/// A float is greater than another if its numeric value is greater than the
/// other. For example, 1e3 is greater than 1e2, and 2e2 is greater than 1e2.
/// Any representable value can be compared without precision loss, e.g. no
/// normalization is done internally.
/// @param signedCoefficientA The signed coefficient of the first floating
/// point number.
/// @param exponentA The exponent of the first floating point number.
/// @param signedCoefficientB The signed coefficient of the second floating
/// point number.
/// @param exponentB The exponent of the second floating point number.
/// @return `true` if the first float is greater than the second, `false`
/// otherwise.
function gt(int256 signedCoefficientA, int256 exponentA, int256 signedCoefficientB, int256 exponentB)
internal
pure
returns (bool)
{
(signedCoefficientA, signedCoefficientB) =
LibDecimalFloatImplementation.compareRescale(signedCoefficientA, exponentA, signedCoefficientB, exponentB);

return signedCoefficientA > signedCoefficientB;
}

/// a^b = 10^(b * log10(a))
Expand Down
Loading