From b29c945bbb15bc2aa14bcab9f8b2222d68f3914f Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sat, 16 Aug 2025 16:28:59 +0400 Subject: [PATCH 01/16] full precision div --- src/error/ErrDecimalFloat.sol | 3 + .../LibDecimalFloatImplementation.sol | 159 ++++++++++++++++-- test/lib/LibCommonResults.sol | 5 +- test/src/lib/LibDecimalFloat.mixed.t.sol | 12 +- test/src/lib/LibDecimalFloat.pow.t.sol | 12 +- test/src/lib/LibDecimalFloat.pow10.t.sol | 6 + .../LibDecimalFloatImplementation.div.t.sol | 28 +-- .../LibDecimalFloatImplementation.pow10.t.sol | 5 +- 8 files changed, 195 insertions(+), 35 deletions(-) diff --git a/src/error/ErrDecimalFloat.sol b/src/error/ErrDecimalFloat.sol index eef6de0a..d9e010d7 100644 --- a/src/error/ErrDecimalFloat.sol +++ b/src/error/ErrDecimalFloat.sol @@ -30,3 +30,6 @@ error LossyConversionFromFloat(int256 signedCoefficient, int256 exponent); /// @dev Thrown when attempting to exponentiate 0^b where b is negative. error ZeroNegativePower(Float b); + +/// @dev Thrown when muldiv internal to division overflows. +error MulDivOverflow(uint256 x, uint256 y, uint256 denominator); diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index 2b1ed275..aec32dcc 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.25; -import {ExponentOverflow, Log10Negative, Log10Zero} from "../../error/ErrDecimalFloat.sol"; +import {ExponentOverflow, Log10Negative, Log10Zero, MulDivOverflow} from "../../error/ErrDecimalFloat.sol"; import { LOG_TABLES, LOG_TABLES_SMALL, @@ -10,6 +10,7 @@ import { ANTI_LOG_TABLES_SMALL } from "../../generated/LogTables.pointers.sol"; import {LibDecimalFloat} from "../LibDecimalFloat.sol"; +import {console2} from "forge-std/console2.sol"; error WithTargetExponentOverflow(int256 signedCoefficient, int256 exponent, int256 targetExponent); @@ -61,6 +62,11 @@ int256 constant MAXIMIZED_ZERO_SIGNED_COEFFICIENT = NORMALIZED_ZERO_SIGNED_COEFF /// @dev The exponent of maximized zero. int256 constant MAXIMIZED_ZERO_EXPONENT = NORMALIZED_ZERO_EXPONENT; +/// @dev The signed coefficient of minimized zero. +int256 constant MINIMIZED_ZERO_SIGNED_COEFFICIENT = 0; +/// @dev The exponent of minimized zero. +int256 constant MINIMIZED_ZERO_EXPONENT = 0; + library LibDecimalFloatImplementation { /// Negates and normalizes a float. /// Equivalent to `0 - x`. @@ -190,14 +196,129 @@ library LibDecimalFloatImplementation { { unchecked { (signedCoefficientA, exponentA) = maximize(signedCoefficientA, exponentA); - (signedCoefficientB, exponentB) = normalize(signedCoefficientB, exponentB); + (signedCoefficientB, exponentB) = maximize(signedCoefficientB, exponentB); - int256 signedCoefficient = signedCoefficientA / signedCoefficientB; - int256 exponent = exponentA - exponentB; + uint256 signedCoefficientAAbs; + if (signedCoefficientA < 0) { + if (signedCoefficientA == type(int256).min) { + signedCoefficientAAbs = uint256(type(int256).max) + 1; + } else { + signedCoefficientAAbs = uint256(-signedCoefficientA); + } + } else { + signedCoefficientAAbs = uint256(signedCoefficientA); + } + uint256 signedCoefficientBAbs; + if (signedCoefficientB < 0) { + if (signedCoefficientB == type(int256).min) { + signedCoefficientBAbs = uint256(type(int256).max) + 1; + } else { + signedCoefficientBAbs = uint256(-signedCoefficientB); + } + } else { + signedCoefficientBAbs = uint256(signedCoefficientB); + } + int256 scale = 1e76; + int256 adjustExponent = 76; + if (signedCoefficientB / scale == 0) { + scale = 1e75; + adjustExponent = 75; + } + uint256 signedCoefficientAbs = mulDiv(signedCoefficientAAbs, uint256(scale), signedCoefficientBAbs); + int256 signedCoefficient = (signedCoefficientA ^ signedCoefficientB) < 0 + ? -int256(signedCoefficientAbs) + : int256(signedCoefficientAbs); + int256 exponent = exponentA - exponentB - adjustExponent; return (signedCoefficient, exponent); } } + /// mulDiv as seen in Open Zeppelin, PRB Math, Solady, and other libraries. + /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512-bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly ("memory-safe") { + let mm := mulmod(x, y, not(0)) + prod0 := mul(x, y) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division. + if (prod1 == 0) { + unchecked { + return prod0 / denominator; + } + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + if (prod1 >= denominator) { + revert MulDivOverflow(x, y, denominator); + } + + //////////////////////////////////////////////////////////////////////////// + // 512 by 256 division + //////////////////////////////////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly ("memory-safe") { + // Compute remainder using the mulmod Yul instruction. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512-bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + unchecked { + // Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow + // because the denominator cannot be zero at this point in the function execution. The result is always >= 1. + // For more detail, see https://cs.stackexchange.com/q/138556/92363. + uint256 lpotdod = denominator & (~denominator + 1); + uint256 flippedLpotdod; + + assembly ("memory-safe") { + // Factor powers of two out of denominator. + denominator := div(denominator, lpotdod) + + // Divide [prod1 prod0] by lpotdod. + prod0 := div(prod0, lpotdod) + + // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one. + // `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits. + // However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693 + flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * flippedLpotdod; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works + // in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + } + } + /// Add two floats together. /// /// Note that because the input values can have arbitrary exponents that may @@ -367,14 +488,9 @@ library LibDecimalFloatImplementation { return signedCoefficientA == signedCoefficientB; } - /// Inverts a float. Equivalent to `1 / x` with modest gas optimizations. + /// Inverts a float. Equivalent to `1 / x`. function inv(int256 signedCoefficient, int256 exponent) internal pure returns (int256, int256) { - (signedCoefficient, exponent) = normalize(signedCoefficient, exponent); - - signedCoefficient = 1e76 / signedCoefficient; - exponent = -exponent - 76; - - return (signedCoefficient, exponent); + return div(1e76, -76, signedCoefficient, exponent); } /// log10(x) for a float x. @@ -535,6 +651,27 @@ library LibDecimalFloatImplementation { } } + // function minimize(int256 signedCoefficient, int256 exponent) internal pure returns (int256, int256) { + // unchecked { + // if (signedCoefficient == 0) { + // return (MINIMIZED_ZERO_SIGNED_COEFFICIENT, MINIMIZED_ZERO_EXPONENT); + // } + + // int256 initialExponent = exponent; + + // while (signedCoefficient % 10 == 0) { + // signedCoefficient /= 10; + // exponent += 1; + // } + + // if (initialExponent > exponent) { + // revert ExponentOverflow(signedCoefficient, exponent); + // } + + // return (signedCoefficient, exponent); + // } + // } + function maximize(int256 signedCoefficient, int256 exponent) internal pure returns (int256, int256) { unchecked { if (signedCoefficient == 0) { diff --git a/test/lib/LibCommonResults.sol b/test/lib/LibCommonResults.sol index 753bb4dc..0f209286 100644 --- a/test/lib/LibCommonResults.sol +++ b/test/lib/LibCommonResults.sol @@ -1,5 +1,6 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.25; -int256 constant ONES = 111111111111111111111111111111111111111; -int256 constant THREES = 333333333333333333333333333333333333333; +int256 constant ONES = 1111111111111111111111111111111111111111111111111111111111111111111111111111; +int256 constant THREES_PACKED = 3333333333333333333333333333333333333333333333333333333333333333333; +int256 constant THREES = 3333333333333333333333333333333333333333333333333333333333333333333333333333; diff --git a/test/src/lib/LibDecimalFloat.mixed.t.sol b/test/src/lib/LibDecimalFloat.mixed.t.sol index 4df03423..ba0c9789 100644 --- a/test/src/lib/LibDecimalFloat.mixed.t.sol +++ b/test/src/lib/LibDecimalFloat.mixed.t.sol @@ -2,7 +2,7 @@ pragma solidity =0.8.25; import {LibDecimalFloat, Float} from "src/lib/LibDecimalFloat.sol"; -import {THREES, ONES} from "../../lib/LibCommonResults.sol"; +import {THREES_PACKED, ONES} from "../../lib/LibCommonResults.sol"; import {Test} from "forge-std/Test.sol"; @@ -10,18 +10,18 @@ contract LibDecimalFloatMixedTest is Test { using LibDecimalFloat for Float; /// (1 / 3) * 555e18 - function testDiv1Over3() external pure { + function testDiv1Over3Mixed() external pure { Float a = LibDecimalFloat.packLossless(1, 0); Float b = LibDecimalFloat.packLossless(3, 0); Float c = a.div(b); (int256 signedCoefficientDiv, int256 exponentDiv) = LibDecimalFloat.unpack(c); - assertEq(signedCoefficientDiv, THREES, "coefficient"); - assertEq(exponentDiv, -39, "exponent"); + assertEq(signedCoefficientDiv, THREES_PACKED, "coefficient"); + assertEq(exponentDiv, -67, "exponent"); Float d = c.mul(LibDecimalFloat.packLossless(555, 18)); (int256 signedCoefficientMul, int256 exponentMul) = LibDecimalFloat.unpack(d); - assertEq(signedCoefficientMul, 184999999999999999999999999999999999999815); - assertEq(exponentMul, -21); + assertEq(signedCoefficientMul, 1849999999999999999999999999999999999999999999999999999999999999999); + assertEq(exponentMul, -46); } } diff --git a/test/src/lib/LibDecimalFloat.pow.t.sol b/test/src/lib/LibDecimalFloat.pow.t.sol index f4a6dcd7..4f356254 100644 --- a/test/src/lib/LibDecimalFloat.pow.t.sol +++ b/test/src/lib/LibDecimalFloat.pow.t.sol @@ -38,9 +38,15 @@ contract LibDecimalFloatPowTest is LogTest { } function testPows() external { - checkPow(5e37, -38, 3e37, -36, 9.32835820895522388059701492537313432835e38, -48); - checkPow(5e37, -38, 6e37, -36, 8.71080139372822299651567944250871080139e38, -57); - // // Issues found in fuzzing from here. + // 0.5 ^ 30 = 9.3132257e-10 + checkPow( + 5e37, -38, 3e37, -36, 9.328358208955223880597014925373134328358208955223880597014925373134e66, -66 - 10 + ); + // 0.5 ^ 60 = 8.6736174e-19 + checkPow( + 5e37, -38, 6e37, -36, 8.710801393728222996515679442508710801393728222996515679442508710801e66, -66 - 19 + ); + // Issues found in fuzzing from here. checkPow(99999, 0, 12182, 0, 1000, 60907); checkPow(1785215562, 0, 18, 0, 3388, 163); } diff --git a/test/src/lib/LibDecimalFloat.pow10.t.sol b/test/src/lib/LibDecimalFloat.pow10.t.sol index 60bf6a5d..960d8657 100644 --- a/test/src/lib/LibDecimalFloat.pow10.t.sol +++ b/test/src/lib/LibDecimalFloat.pow10.t.sol @@ -27,6 +27,12 @@ contract LibDecimalFloatPow10Test is LogTest { } else { Float floatPower10 = this.pow10External(float); (int256 signedCoefficientUnpacked, int256 exponentUnpacked) = floatPower10.unpack(); + + // Compensate for the implied pack and unpack. + (Float resultPacked, bool lossless) = LibDecimalFloat.packLossy(signedCoefficient, exponent); + (lossless); + (signedCoefficient, exponent) = resultPacked.unpack(); + assertEq(signedCoefficient, signedCoefficientUnpacked); assertEq(exponent, exponentUnpacked); } diff --git a/test/src/lib/implementation/LibDecimalFloatImplementation.div.t.sol b/test/src/lib/implementation/LibDecimalFloatImplementation.div.t.sol index 2f3f3357..cb5f454d 100644 --- a/test/src/lib/implementation/LibDecimalFloatImplementation.div.t.sol +++ b/test/src/lib/implementation/LibDecimalFloatImplementation.div.t.sol @@ -40,12 +40,12 @@ contract LibDecimalFloatImplementationDivTest is Test { /// 1 / 3 function testDiv1Over3() external pure { - checkDiv(1, 0, 3, 0, THREES, -39); + checkDiv(1, 0, 3, 0, THREES, -76); } /// - 1 / 3 function testDivNegative1Over3() external pure { - checkDiv(-1, 0, 3, 0, -THREES, -39); + checkDiv(-1, 0, 3, 0, -THREES, -76); } /// 1 / 3 gas @@ -56,22 +56,22 @@ contract LibDecimalFloatImplementationDivTest is Test { /// 1e18 / 3 function testDiv1e18Over3() external pure { - checkDiv(1e18, 0, 3, 0, THREES, -21); + checkDiv(1e18, 0, 3, 0, THREES, -58); } /// 10,0 / 1e38,-37 == 1 function testDivTenOverOOMs() external pure { - checkDiv(10, 0, 1e38, -37, 1e39, -39); + checkDiv(10, 0, 1e38, -37, 1e76, -76); } /// 1e38,-37 / 2,0 == 5 function testDivOOMsOverTen() external pure { - checkDiv(1e38, -37, 2, 0, 5e38, -38); + checkDiv(1e38, -37, 2, 0, 5e75, -75); } /// 5e37,-37 / 2e37,-37 == 2.5 function testDivOOMs5and2() external pure { - checkDiv(5e37, -37, 2e37, -37, 25e38, -39); + checkDiv(5e37, -37, 2e37, -37, 2.5e76, -76); } /// (1 / 9) / (1 / 3) == 0.333.. @@ -79,18 +79,24 @@ contract LibDecimalFloatImplementationDivTest is Test { // 1 / 9 (int256 signedCoefficientA, int256 exponentA) = LibDecimalFloatImplementation.div(1, 0, 9, 0); assertEq(signedCoefficientA, ONES); - assertEq(exponentA, -39); + assertEq(exponentA, -76); // 1 / 3 (int256 signedCoefficientB, int256 exponentB) = LibDecimalFloatImplementation.div(1, 0, 3, 0); assertEq(signedCoefficientB, THREES); - assertEq(exponentB, -39); + assertEq(exponentB, -76); // (1 / 9) / (1 / 3) (int256 signedCoefficient, int256 exponent) = LibDecimalFloatImplementation.div(signedCoefficientA, exponentA, signedCoefficientB, exponentB); - assertEq(signedCoefficient, 333333333333333333333333333333333333336); - assertEq(exponent, -39); + assertEq(signedCoefficient, THREES); + assertEq(exponent, -76); + + // (1 / 3) / (1 / 9) == 3 + (signedCoefficient, exponent) = + LibDecimalFloatImplementation.div(signedCoefficientB, exponentB, signedCoefficientA, exponentA); + assertEq(signedCoefficient, 3e76); + assertEq(exponent, -76); } /// forge-config: default.fuzz.runs = 100 @@ -102,7 +108,7 @@ contract LibDecimalFloatImplementationDivTest is Test { int256 di = 0; while (true) { int256 i = 1; - int256 j = -39 - di; + int256 j = -76 - di; while (true) { // want to see full precision on the THREES regardless of the // scale of the numerator and denominator. diff --git a/test/src/lib/implementation/LibDecimalFloatImplementation.pow10.t.sol b/test/src/lib/implementation/LibDecimalFloatImplementation.pow10.t.sol index de9c7ca3..5324d6ec 100644 --- a/test/src/lib/implementation/LibDecimalFloatImplementation.pow10.t.sol +++ b/test/src/lib/implementation/LibDecimalFloatImplementation.pow10.t.sol @@ -32,7 +32,7 @@ contract LibDecimalFloatImplementationPow10Test is LogTest { checkPow10(1, 4, 1000, 9997); } - function testExactLookups() external { + function testExactLookupsPow10() external { // 10^2 = 100 checkPow10(2, 0, 1000, -1); // 10^3 = 1000 @@ -56,7 +56,8 @@ contract LibDecimalFloatImplementationPow10Test is LogTest { checkPow10(0.5e37, -37, 3162, -3); checkPow10(0.3e37, -37, 1995, -3); - checkPow10(-0.3e37, -37, 0.501253132832080200501253132832080200501e39, -39); + // 10^-0.3 = 0.50118723362 + checkPow10(-0.3e37, -37, 0.5012531328320802005012531328320802005012531328320802005012531328320802005012e76, -76); } function testInterpolatedLookupsPower() external { From 7a93d409bbbc06a25522787c9ed86b42234659c4 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sat, 16 Aug 2025 16:32:46 +0400 Subject: [PATCH 02/16] snapshot --- .gas-snapshot | 128 +++++++++--------- .../LibDecimalFloatImplementation.sol | 22 --- 2 files changed, 64 insertions(+), 86 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 67f4143e..39386b55 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,35 +1,35 @@ -DecimalFloatAbsTest:testAbsDeployed(bytes32) (runs: 5118, μ: 2575478, ~: 2575421) -DecimalFloatAddTest:testAddDeployed(bytes32,bytes32) (runs: 5118, μ: 2579527, ~: 2579617) -DecimalFloatCeilTest:testCeilDeployed(bytes32) (runs: 5118, μ: 2575504, ~: 2575134) -DecimalFloatConstantsTest:testEDeployed() (gas: 2574664) -DecimalFloatConstantsTest:testMaxNegativeValueDeployed() (gas: 2574696) -DecimalFloatConstantsTest:testMaxPositiveValueDeployed() (gas: 2574654) -DecimalFloatConstantsTest:testMinNegativeValueDeployed() (gas: 2574629) -DecimalFloatConstantsTest:testMinPositiveValueDeployed() (gas: 2574608) -DecimalFloatDivTest:testDivDeployed(bytes32,bytes32) (runs: 5118, μ: 2578204, ~: 2578195) -DecimalFloatEqTest:testEqDeployed(bytes32,bytes32) (runs: 5118, μ: 2575864, ~: 2575789) -DecimalFloatFloorTest:testFloorDeployed(bytes32) (runs: 5118, μ: 2575316, ~: 2575132) -DecimalFloatFormatTest:testFormatDeployed(bytes32) (runs: 5118, μ: 2579467, ~: 2579297) -DecimalFloatFracTest:testFracDeployed(bytes32) (runs: 5118, μ: 2575708, ~: 2575692) -DecimalFloatFromFixedDecimalLosslessTest:testFromFixedDecimalLosslessDeployed(uint256,uint8) (runs: 5118, μ: 2576261, ~: 2576196) -DecimalFloatFromFixedDecimalLossyTest:testFromFixedDecimalLossyDeployed(uint256,uint8) (runs: 5118, μ: 2576747, ~: 2576666) -DecimalFloatGtTest:testGtDeployed(bytes32,bytes32) (runs: 5118, μ: 2575806, ~: 2575731) -DecimalFloatGteTest:testGteDeployed(bytes32,bytes32) (runs: 5118, μ: 2575791, ~: 2575717) -DecimalFloatInvTest:testInvDeployed(bytes32) (runs: 5118, μ: 2577047, ~: 2576972) -DecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5118, μ: 2574974, ~: 2574974) -DecimalFloatLtTest:testLtDeployed(bytes32,bytes32) (runs: 5118, μ: 2575783, ~: 2575708) -DecimalFloatLteTest:testLteDeployed(bytes32,bytes32) (runs: 5118, μ: 2575837, ~: 2575761) -DecimalFloatMaxTest:testMaxDeployed(bytes32,bytes32) (runs: 5118, μ: 2575845, ~: 2575783) -DecimalFloatMinTest:testMinDeployed(bytes32,bytes32) (runs: 5118, μ: 2575865, ~: 2575803) -DecimalFloatMinusTest:testMinusDeployed(bytes32) (runs: 5118, μ: 2575579, ~: 2575579) -DecimalFloatMulTest:testMulDeployed(bytes32,bytes32) (runs: 5118, μ: 2577678, ~: 2578739) +DecimalFloatAbsTest:testAbsDeployed(bytes32) (runs: 5118, μ: 2653060, ~: 2653003) +DecimalFloatAddTest:testAddDeployed(bytes32,bytes32) (runs: 5118, μ: 2657117, ~: 2657199) +DecimalFloatCeilTest:testCeilDeployed(bytes32) (runs: 5118, μ: 2653087, ~: 2652716) +DecimalFloatConstantsTest:testEDeployed() (gas: 2652246) +DecimalFloatConstantsTest:testMaxNegativeValueDeployed() (gas: 2652278) +DecimalFloatConstantsTest:testMaxPositiveValueDeployed() (gas: 2652236) +DecimalFloatConstantsTest:testMinNegativeValueDeployed() (gas: 2652211) +DecimalFloatConstantsTest:testMinPositiveValueDeployed() (gas: 2652190) +DecimalFloatDivTest:testDivDeployed(bytes32,bytes32) (runs: 5118, μ: 2658139, ~: 2658198) +DecimalFloatEqTest:testEqDeployed(bytes32,bytes32) (runs: 5118, μ: 2653446, ~: 2653371) +DecimalFloatFloorTest:testFloorDeployed(bytes32) (runs: 5118, μ: 2652897, ~: 2652714) +DecimalFloatFormatTest:testFormatDeployed(bytes32) (runs: 5118, μ: 2657051, ~: 2656907) +DecimalFloatFracTest:testFracDeployed(bytes32) (runs: 5118, μ: 2653290, ~: 2653274) +DecimalFloatFromFixedDecimalLosslessTest:testFromFixedDecimalLosslessDeployed(uint256,uint8) (runs: 5118, μ: 2653844, ~: 2653778) +DecimalFloatFromFixedDecimalLossyTest:testFromFixedDecimalLossyDeployed(uint256,uint8) (runs: 5118, μ: 2654334, ~: 2654248) +DecimalFloatGtTest:testGtDeployed(bytes32,bytes32) (runs: 5118, μ: 2653387, ~: 2653313) +DecimalFloatGteTest:testGteDeployed(bytes32,bytes32) (runs: 5118, μ: 2653373, ~: 2653299) +DecimalFloatInvTest:testInvDeployed(bytes32) (runs: 5118, μ: 2656967, ~: 2657003) +DecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5118, μ: 2652556, ~: 2652556) +DecimalFloatLtTest:testLtDeployed(bytes32,bytes32) (runs: 5118, μ: 2653364, ~: 2653290) +DecimalFloatLteTest:testLteDeployed(bytes32,bytes32) (runs: 5118, μ: 2653417, ~: 2653343) +DecimalFloatMaxTest:testMaxDeployed(bytes32,bytes32) (runs: 5118, μ: 2653426, ~: 2653365) +DecimalFloatMinTest:testMinDeployed(bytes32,bytes32) (runs: 5118, μ: 2653447, ~: 2653385) +DecimalFloatMinusTest:testMinusDeployed(bytes32) (runs: 5118, μ: 2653161, ~: 2653161) +DecimalFloatMulTest:testMulDeployed(bytes32,bytes32) (runs: 5118, μ: 2655259, ~: 2656321) DecimalFloatPackLosslessTest:testPackDeployed(int224,int32) (runs: 5118, μ: 158769, ~: 158769) -DecimalFloatParseTest:testParseDeployed(string) (runs: 5118, μ: 2578211, ~: 2578080) -DecimalFloatPowTest:testPowDeployed(bytes32,bytes32) (runs: 5118, μ: 2586874, ~: 2583812) -DecimalFloatSqrtTest:testSqrtDeployed(bytes32) (runs: 5118, μ: 2586169, ~: 2584526) -DecimalFloatSubTest:testSubDeployed(bytes32,bytes32) (runs: 5118, μ: 2579886, ~: 2579917) -DecimalFloatToFixedDecimalLosslessTest:testToFixedDecimalLosslessDeployed(bytes32,uint8) (runs: 5118, μ: 2576909, ~: 2576779) -DecimalFloatToFixedDecimalLossyTest:testToFixedDecimalLossyDeployed(bytes32,uint8) (runs: 5118, μ: 2577046, ~: 2577308) +DecimalFloatParseTest:testParseDeployed(string) (runs: 5118, μ: 2655793, ~: 2655662) +DecimalFloatPowTest:testPowDeployed(bytes32,bytes32) (runs: 5118, μ: 2665139, ~: 2661394) +DecimalFloatSqrtTest:testSqrtDeployed(bytes32) (runs: 5118, μ: 2664432, ~: 2662108) +DecimalFloatSubTest:testSubDeployed(bytes32,bytes32) (runs: 5118, μ: 2657477, ~: 2657499) +DecimalFloatToFixedDecimalLosslessTest:testToFixedDecimalLosslessDeployed(bytes32,uint8) (runs: 5118, μ: 2654482, ~: 2654361) +DecimalFloatToFixedDecimalLossyTest:testToFixedDecimalLossyDeployed(bytes32,uint8) (runs: 5118, μ: 2654617, ~: 2654890) LibDecimalFloatAbsTest:testAbsMinValue(int32) (runs: 5117, μ: 5121, ~: 5121) LibDecimalFloatAbsTest:testAbsNegative(int256,int32) (runs: 5118, μ: 10475, ~: 10702) LibDecimalFloatAbsTest:testAbsNonNegative(int256,int32) (runs: 5118, μ: 9640, ~: 9392) @@ -79,7 +79,7 @@ LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncate(int256,int256,uint8) LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncateLossless() (gas: 14523) LibDecimalFloatDecimalTest:testToFixedDecimalLossyUnderflow(int256,int256,uint8) (runs: 5118, μ: 13739, ~: 13602) LibDecimalFloatDecimalTest:testToFixedDecimalLossyZero(int256,uint8) (runs: 5118, μ: 4598, ~: 4598) -LibDecimalFloatDivTest:testDivPacked(bytes32,bytes32) (runs: 5118, μ: 8293, ~: 8263) +LibDecimalFloatDivTest:testDivPacked(bytes32,bytes32) (runs: 5118, μ: 10668, ~: 10745) LibDecimalFloatEqTest:testEqPacked(bytes32,bytes32) (runs: 5118, μ: 5524, ~: 5450) LibDecimalFloatEqTest:testEqXNotYExponents(bytes32,bytes32) (runs: 5118, μ: 4341, ~: 4234) LibDecimalFloatEqTest:testEqZero(int32) (runs: 5118, μ: 5133, ~: 5133) @@ -144,16 +144,16 @@ LibDecimalFloatImplementationAddTest:testGasAddOne() (gas: 1342) LibDecimalFloatImplementationAddTest:testGasAddZero() (gas: 360) LibDecimalFloatImplementationAddTest:testOverflowChecks(int256,int256) (runs: 5118, μ: 3857, ~: 3843) LibDecimalFloatImplementationCharacteristicMantissaTest:testCharacteristicMantissaExamples() (gas: 30611) -LibDecimalFloatImplementationDivTest:testDiv1Over3() (gas: 5987) -LibDecimalFloatImplementationDivTest:testDiv1Over3Gas0() (gas: 923) -LibDecimalFloatImplementationDivTest:testDiv1Over3Gas10() (gas: 10560) -LibDecimalFloatImplementationDivTest:testDiv1Over9Over1Over3() (gas: 9596) -LibDecimalFloatImplementationDivTest:testDiv1e18Over3() (gas: 5646) -LibDecimalFloatImplementationDivTest:testDivNegative1Over3() (gas: 6047) -LibDecimalFloatImplementationDivTest:testDivOOMs5and2() (gas: 5055) -LibDecimalFloatImplementationDivTest:testDivOOMsOverTen() (gas: 5957) -LibDecimalFloatImplementationDivTest:testDivTenOverOOMs() (gas: 5551) -LibDecimalFloatImplementationDivTest:testUnnormalizedThreesDiv0(int256,int256) (runs: 122, μ: 20842375, ~: 20842008) +LibDecimalFloatImplementationDivTest:testDiv1Over3() (gas: 6621) +LibDecimalFloatImplementationDivTest:testDiv1Over3Gas0() (gas: 1769) +LibDecimalFloatImplementationDivTest:testDiv1Over3Gas10() (gas: 14582) +LibDecimalFloatImplementationDivTest:testDiv1Over9Over1Over3() (gas: 12791) +LibDecimalFloatImplementationDivTest:testDiv1e18Over3() (gas: 6280) +LibDecimalFloatImplementationDivTest:testDivNegative1Over3() (gas: 6719) +LibDecimalFloatImplementationDivTest:testDivOOMs5and2() (gas: 5901) +LibDecimalFloatImplementationDivTest:testDivOOMsOverTen() (gas: 6591) +LibDecimalFloatImplementationDivTest:testDivTenOverOOMs() (gas: 6504) +LibDecimalFloatImplementationDivTest:testUnnormalizedThreesDiv0(int256,int256) (runs: 122, μ: 24551459, ~: 24551233) LibDecimalFloatImplementationEqTest:testEqGasAZero() (gas: 430) LibDecimalFloatImplementationEqTest:testEqGasBZero() (gas: 473) LibDecimalFloatImplementationEqTest:testEqGasBothZero() (gas: 450) @@ -167,13 +167,13 @@ LibDecimalFloatImplementationEqTest:testEqXEAnyVsXEAny(int256,int256,int256) (ru LibDecimalFloatImplementationEqTest:testEqXEqY(int256,int256,int256,int256) (runs: 5118, μ: 732, ~: 753) LibDecimalFloatImplementationEqTest:testEqXNotY(int256,int256,int256,int256) (runs: 5118, μ: 3928, ~: 3953) LibDecimalFloatImplementationEqTest:testEqZero(int256,int256) (runs: 5118, μ: 3440, ~: 3440) -LibDecimalFloatImplementationInvTest:testInvGas0() (gas: 734) -LibDecimalFloatImplementationInvTest:testInvReference(int256,int256) (runs: 5116, μ: 12416, ~: 12356) -LibDecimalFloatImplementationInvTest:testInvSlowGas0() (gas: 948) +LibDecimalFloatImplementationInvTest:testInvGas0() (gas: 1596) +LibDecimalFloatImplementationInvTest:testInvReference(int256,int256) (runs: 5116, μ: 13635, ~: 13595) +LibDecimalFloatImplementationInvTest:testInvSlowGas0() (gas: 1780) LibDecimalFloatImplementationLog10Test:testExactLogs() (gas: 1263178) LibDecimalFloatImplementationLog10Test:testExactLookupsLog10() (gas: 1280250) -LibDecimalFloatImplementationLog10Test:testInterpolatedLookups() (gas: 1260273) -LibDecimalFloatImplementationLog10Test:testSub1() (gas: 1256794) +LibDecimalFloatImplementationLog10Test:testInterpolatedLookups() (gas: 1260152) +LibDecimalFloatImplementationLog10Test:testSub1() (gas: 1258137) LibDecimalFloatImplementationMaximizeTest:testMaximizedEverything(int256,int256) (runs: 5118, μ: 9478, ~: 9455) LibDecimalFloatImplementationMaximizeTest:testMaximizedExamples() (gas: 165819) LibDecimalFloatImplementationMaximizeTest:testMaximizedIdempotent(int256,int256) (runs: 5118, μ: 9903, ~: 9868) @@ -193,10 +193,10 @@ LibDecimalFloatImplementationNormalizeTest:testExamples() (gas: 160899) LibDecimalFloatImplementationNormalizeTest:testIdempotent(int256,int256) (runs: 5118, μ: 9875, ~: 9808) LibDecimalFloatImplementationNormalizeTest:testIsNormalizedReference(int256,int256) (runs: 5118, μ: 3533, ~: 3539) LibDecimalFloatImplementationNormalizeTest:testNormalized(int256,int256) (runs: 5118, μ: 9415, ~: 9348) -LibDecimalFloatImplementationPow10Test:testExactLookups() (gas: 1281984) -LibDecimalFloatImplementationPow10Test:testExactPows() (gas: 1260129) -LibDecimalFloatImplementationPow10Test:testInterpolatedLookupsPower() (gas: 1283750) -LibDecimalFloatImplementationPow10Test:testNoRevert(int224,int32) (runs: 5110, μ: 1258970, ~: 1259175) +LibDecimalFloatImplementationPow10Test:testExactLookupsPow10() (gas: 1282682) +LibDecimalFloatImplementationPow10Test:testExactPows() (gas: 1260107) +LibDecimalFloatImplementationPow10Test:testInterpolatedLookupsPower() (gas: 1283525) +LibDecimalFloatImplementationPow10Test:testNoRevert(int224,int32) (runs: 5108, μ: 1259251, ~: 1260162) LibDecimalFloatImplementationSubTest:testSubIsAdd(int256,int256,int256,int256) (runs: 5118, μ: 15800, ~: 15832) LibDecimalFloatImplementationSubTest:testSubMinSignedValue(int256,int256,int256) (runs: 5118, μ: 14990, ~: 14932) LibDecimalFloatImplementationSubTest:testSubOneFromMax() (gas: 6517) @@ -207,12 +207,12 @@ LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLarger LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerTargetExponentNoRevert(int256,int256,int256) (runs: 5118, μ: 11668, ~: 11718) LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentSameExponentNoop(int256,int256) (runs: 5118, μ: 3676, ~: 3676) LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentSmallerExponentNoRevert(int256,int256,int256) (runs: 5110, μ: 13874, ~: 13665) -LibDecimalFloatInvTest:testInvMem(bytes32) (runs: 5118, μ: 7321, ~: 7246) +LibDecimalFloatInvTest:testInvMem(bytes32) (runs: 5118, μ: 9670, ~: 9726) LibDecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5118, μ: 3899, ~: 3899) LibDecimalFloatIsZeroTest:testIsZeroEqZero(bytes32) (runs: 5118, μ: 3527, ~: 3527) LibDecimalFloatIsZeroTest:testIsZeroExamples(int32) (runs: 5118, μ: 4477, ~: 4477) LibDecimalFloatIsZeroTest:testNotIsZero(int224,int32) (runs: 5116, μ: 3896, ~: 3896) -LibDecimalFloatLog10Test:testLog10Packed(bytes32) (runs: 5118, μ: 1651243, ~: 1270937) +LibDecimalFloatLog10Test:testLog10Packed(bytes32) (runs: 5118, μ: 1652204, ~: 1270767) LibDecimalFloatLtTest:testLtExamples() (gas: 3994) LibDecimalFloatLtTest:testLtGasAZero() (gas: 946) LibDecimalFloatLtTest:testLtGasBZero() (gas: 1012) @@ -253,21 +253,21 @@ LibDecimalFloatMinTest:testMinXYEqual(bytes32) (runs: 5118, μ: 5292, ~: 5292) LibDecimalFloatMinTest:testMinXYGreater(bytes32,bytes32) (runs: 5110, μ: 6074, ~: 5961) LibDecimalFloatMinTest:testMinXYLess(bytes32,bytes32) (runs: 5104, μ: 6087, ~: 5972) LibDecimalFloatMinusTest:testMinusPacked(bytes32) (runs: 5118, μ: 5550, ~: 5550) -LibDecimalFloatMixedTest:testDiv1Over3() (gas: 8175) +LibDecimalFloatMixedTest:testDiv1Over3Mixed() (gas: 9513) LibDecimalFloatMulTest:testMulPacked(bytes32,bytes32) (runs: 5118, μ: 7889, ~: 8837) LibDecimalFloatPackTest:testPartsRoundTrip(int224,int32) (runs: 5118, μ: 5352, ~: 5352) -LibDecimalFloatPow10Test:testPow10Packed(bytes32) (runs: 5118, μ: 1644250, ~: 1257848) -LibDecimalFloatPowTest:testNegativePowError(bytes32,bytes32) (runs: 5117, μ: 1248480, ~: 1248447) -LibDecimalFloatPowTest:testPowAZero(int32,bytes32) (runs: 5111, μ: 1246471, ~: 1246471) +LibDecimalFloatPow10Test:testPow10Packed(bytes32) (runs: 5118, μ: 1648539, ~: 1258791) +LibDecimalFloatPowTest:testNegativePowError(bytes32,bytes32) (runs: 5118, μ: 1248480, ~: 1248447) +LibDecimalFloatPowTest:testPowAZero(int32,bytes32) (runs: 5110, μ: 1246471, ~: 1246471) LibDecimalFloatPowTest:testPowAZeroNegative(bytes32) (runs: 5098, μ: 1246870, ~: 1246870) LibDecimalFloatPowTest:testPowBZero(bytes32,int32) (runs: 5118, μ: 1246058, ~: 1246058) -LibDecimalFloatPowTest:testPows() (gas: 1307988) -LibDecimalFloatPowTest:testRoundTripFuzzPow(bytes32,bytes32) (runs: 5118, μ: 1260704, ~: 1257620) -LibDecimalFloatPowTest:testRoundTripSimple() (gas: 1466189) -LibDecimalFloatSqrtTest:testRoundTripFuzzSqrt(int224,int32) (runs: 5118, μ: 1291727, ~: 1289446) -LibDecimalFloatSqrtTest:testSqrt() (gas: 1293117) -LibDecimalFloatSqrtTest:testSqrtNegative(bytes32) (runs: 5118, μ: 1248101, ~: 1248059) -LibDecimalFloatSqrtTest:testSqrtRoundTrip() (gas: 1392528) +LibDecimalFloatPowTest:testPows() (gas: 1312710) +LibDecimalFloatPowTest:testRoundTripFuzzPow(bytes32,bytes32) (runs: 5118, μ: 1261607, ~: 1258764) +LibDecimalFloatPowTest:testRoundTripSimple() (gas: 1509162) +LibDecimalFloatSqrtTest:testRoundTripFuzzSqrt(int224,int32) (runs: 5118, μ: 1293488, ~: 1293796) +LibDecimalFloatSqrtTest:testSqrt() (gas: 1293184) +LibDecimalFloatSqrtTest:testSqrtNegative(bytes32) (runs: 5118, μ: 1248100, ~: 1248059) +LibDecimalFloatSqrtTest:testSqrtRoundTrip() (gas: 1400335) LibDecimalFloatSubTest:testSubPacked(bytes32,bytes32) (runs: 5118, μ: 9973, ~: 9995) LibFormatDecimalFloatTest:testFormatDecimalExamples() (gas: 133439) LibFormatDecimalFloatTest:testFormatDecimalRoundTrip(uint256) (runs: 5118, μ: 25209, ~: 20105) diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index aec32dcc..dfde586c 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -10,7 +10,6 @@ import { ANTI_LOG_TABLES_SMALL } from "../../generated/LogTables.pointers.sol"; import {LibDecimalFloat} from "../LibDecimalFloat.sol"; -import {console2} from "forge-std/console2.sol"; error WithTargetExponentOverflow(int256 signedCoefficient, int256 exponent, int256 targetExponent); @@ -651,27 +650,6 @@ library LibDecimalFloatImplementation { } } - // function minimize(int256 signedCoefficient, int256 exponent) internal pure returns (int256, int256) { - // unchecked { - // if (signedCoefficient == 0) { - // return (MINIMIZED_ZERO_SIGNED_COEFFICIENT, MINIMIZED_ZERO_EXPONENT); - // } - - // int256 initialExponent = exponent; - - // while (signedCoefficient % 10 == 0) { - // signedCoefficient /= 10; - // exponent += 1; - // } - - // if (initialExponent > exponent) { - // revert ExponentOverflow(signedCoefficient, exponent); - // } - - // return (signedCoefficient, exponent); - // } - // } - function maximize(int256 signedCoefficient, int256 exponent) internal pure returns (int256, int256) { unchecked { if (signedCoefficient == 0) { From 7975cd5e40e993d813f674b1098a7757a76fea64 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sat, 16 Aug 2025 16:38:17 +0400 Subject: [PATCH 03/16] lint --- .../implementation/LibDecimalFloatImplementation.sol | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index dfde586c..83e26c32 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -194,9 +194,14 @@ library LibDecimalFloatImplementation { returns (int256, int256) { unchecked { + // Move both coefficients into the e75/e76 range, so that the result + // of division will also be roughly maximized, and we can easily + // optimise precision. (signedCoefficientA, exponentA) = maximize(signedCoefficientA, exponentA); (signedCoefficientB, exponentB) = maximize(signedCoefficientB, exponentB); + // mulDiv only works with unsigned integers, so get the aboslute + // values of the coefficients. uint256 signedCoefficientAAbs; if (signedCoefficientA < 0) { if (signedCoefficientA == type(int256).min) { @@ -217,6 +222,13 @@ library LibDecimalFloatImplementation { } else { signedCoefficientBAbs = uint256(signedCoefficientB); } + + // We are going to scale the numerator up by the largest power of ten + // that is smaller than the denominator. This will always overflow + // internally to the mulDiv during the initial multiplication, in + // 512 bits, but will subsequently always be reduced back down to + // fit in 256 bits by the division of a denominator that is larger + // than the scale up. int256 scale = 1e76; int256 adjustExponent = 76; if (signedCoefficientB / scale == 0) { From 1f32d2745e4a0ba25a29dc11c8fbdbc09ac2b8e0 Mon Sep 17 00:00:00 2001 From: David Meister Date: Sat, 16 Aug 2025 16:38:55 +0400 Subject: [PATCH 04/16] Update src/error/ErrDecimalFloat.sol Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/error/ErrDecimalFloat.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error/ErrDecimalFloat.sol b/src/error/ErrDecimalFloat.sol index d9e010d7..cd4cfd0c 100644 --- a/src/error/ErrDecimalFloat.sol +++ b/src/error/ErrDecimalFloat.sol @@ -31,5 +31,5 @@ error LossyConversionFromFloat(int256 signedCoefficient, int256 exponent); /// @dev Thrown when attempting to exponentiate 0^b where b is negative. error ZeroNegativePower(Float b); -/// @dev Thrown when muldiv internal to division overflows. +/// @dev Thrown when mulDiv internal to division overflows. error MulDivOverflow(uint256 x, uint256 y, uint256 denominator); From 8949cb3090e5d006abfb8e2444a73a5b65de9257 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sun, 17 Aug 2025 15:17:23 +0400 Subject: [PATCH 05/16] lint --- src/lib/implementation/LibDecimalFloatImplementation.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index 83e26c32..e2092a92 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -195,8 +195,7 @@ library LibDecimalFloatImplementation { { unchecked { // Move both coefficients into the e75/e76 range, so that the result - // of division will also be roughly maximized, and we can easily - // optimise precision. + // of division will not cause a mulDiv overflow. (signedCoefficientA, exponentA) = maximize(signedCoefficientA, exponentA); (signedCoefficientB, exponentB) = maximize(signedCoefficientB, exponentB); From 5fe88317702bdeb9745333ea1f363034361afe03 Mon Sep 17 00:00:00 2001 From: David Meister Date: Mon, 18 Aug 2025 14:48:07 +0400 Subject: [PATCH 06/16] Update src/lib/implementation/LibDecimalFloatImplementation.sol Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/lib/implementation/LibDecimalFloatImplementation.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index e2092a92..9e5b0a2d 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -199,7 +199,7 @@ library LibDecimalFloatImplementation { (signedCoefficientA, exponentA) = maximize(signedCoefficientA, exponentA); (signedCoefficientB, exponentB) = maximize(signedCoefficientB, exponentB); - // mulDiv only works with unsigned integers, so get the aboslute + // mulDiv only works with unsigned integers, so get the absolute // values of the coefficients. uint256 signedCoefficientAAbs; if (signedCoefficientA < 0) { From 63bd634bdc0e97e828151a75cf4652a334b74dc2 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 18 Aug 2025 14:49:54 +0400 Subject: [PATCH 07/16] lint --- src/lib/implementation/LibDecimalFloatImplementation.sol | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index 9e5b0a2d..1dab61a4 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -61,11 +61,6 @@ int256 constant MAXIMIZED_ZERO_SIGNED_COEFFICIENT = NORMALIZED_ZERO_SIGNED_COEFF /// @dev The exponent of maximized zero. int256 constant MAXIMIZED_ZERO_EXPONENT = NORMALIZED_ZERO_EXPONENT; -/// @dev The signed coefficient of minimized zero. -int256 constant MINIMIZED_ZERO_SIGNED_COEFFICIENT = 0; -/// @dev The exponent of minimized zero. -int256 constant MINIMIZED_ZERO_EXPONENT = 0; - library LibDecimalFloatImplementation { /// Negates and normalizes a float. /// Equivalent to `0 - x`. From 887f4a7c180ba5ffcb64a9fb08b067c6a9a62995 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 18 Aug 2025 14:56:01 +0400 Subject: [PATCH 08/16] slither --- src/lib/implementation/LibDecimalFloatImplementation.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index 1dab61a4..476bcbb0 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -288,9 +288,11 @@ library LibDecimalFloatImplementation { assembly ("memory-safe") { // Factor powers of two out of denominator. + // slither-disable-next-line divide-before-multiply denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. + // slither-disable-next-line divide-before-multiply prod0 := div(prod0, lpotdod) // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one. @@ -305,6 +307,7 @@ library LibDecimalFloatImplementation { // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. + // slither-disable-next-line incorrect-exp uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works From d0c8201d4b60d19ae8635fb499f1c998dce14e9e Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 18 Aug 2025 15:06:05 +0400 Subject: [PATCH 09/16] lint div implementation --- .gas-snapshot | 396 +++++++++--------- .../LibDecimalFloatImplementation.sol | 6 +- 2 files changed, 201 insertions(+), 201 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 39386b55..4f2003f6 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,277 +1,277 @@ -DecimalFloatAbsTest:testAbsDeployed(bytes32) (runs: 5118, μ: 2653060, ~: 2653003) -DecimalFloatAddTest:testAddDeployed(bytes32,bytes32) (runs: 5118, μ: 2657117, ~: 2657199) -DecimalFloatCeilTest:testCeilDeployed(bytes32) (runs: 5118, μ: 2653087, ~: 2652716) -DecimalFloatConstantsTest:testEDeployed() (gas: 2652246) -DecimalFloatConstantsTest:testMaxNegativeValueDeployed() (gas: 2652278) -DecimalFloatConstantsTest:testMaxPositiveValueDeployed() (gas: 2652236) -DecimalFloatConstantsTest:testMinNegativeValueDeployed() (gas: 2652211) -DecimalFloatConstantsTest:testMinPositiveValueDeployed() (gas: 2652190) -DecimalFloatDivTest:testDivDeployed(bytes32,bytes32) (runs: 5118, μ: 2658139, ~: 2658198) -DecimalFloatEqTest:testEqDeployed(bytes32,bytes32) (runs: 5118, μ: 2653446, ~: 2653371) -DecimalFloatFloorTest:testFloorDeployed(bytes32) (runs: 5118, μ: 2652897, ~: 2652714) -DecimalFloatFormatTest:testFormatDeployed(bytes32) (runs: 5118, μ: 2657051, ~: 2656907) -DecimalFloatFracTest:testFracDeployed(bytes32) (runs: 5118, μ: 2653290, ~: 2653274) -DecimalFloatFromFixedDecimalLosslessTest:testFromFixedDecimalLosslessDeployed(uint256,uint8) (runs: 5118, μ: 2653844, ~: 2653778) -DecimalFloatFromFixedDecimalLossyTest:testFromFixedDecimalLossyDeployed(uint256,uint8) (runs: 5118, μ: 2654334, ~: 2654248) -DecimalFloatGtTest:testGtDeployed(bytes32,bytes32) (runs: 5118, μ: 2653387, ~: 2653313) -DecimalFloatGteTest:testGteDeployed(bytes32,bytes32) (runs: 5118, μ: 2653373, ~: 2653299) -DecimalFloatInvTest:testInvDeployed(bytes32) (runs: 5118, μ: 2656967, ~: 2657003) -DecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5118, μ: 2652556, ~: 2652556) -DecimalFloatLtTest:testLtDeployed(bytes32,bytes32) (runs: 5118, μ: 2653364, ~: 2653290) -DecimalFloatLteTest:testLteDeployed(bytes32,bytes32) (runs: 5118, μ: 2653417, ~: 2653343) -DecimalFloatMaxTest:testMaxDeployed(bytes32,bytes32) (runs: 5118, μ: 2653426, ~: 2653365) -DecimalFloatMinTest:testMinDeployed(bytes32,bytes32) (runs: 5118, μ: 2653447, ~: 2653385) -DecimalFloatMinusTest:testMinusDeployed(bytes32) (runs: 5118, μ: 2653161, ~: 2653161) -DecimalFloatMulTest:testMulDeployed(bytes32,bytes32) (runs: 5118, μ: 2655259, ~: 2656321) -DecimalFloatPackLosslessTest:testPackDeployed(int224,int32) (runs: 5118, μ: 158769, ~: 158769) -DecimalFloatParseTest:testParseDeployed(string) (runs: 5118, μ: 2655793, ~: 2655662) -DecimalFloatPowTest:testPowDeployed(bytes32,bytes32) (runs: 5118, μ: 2665139, ~: 2661394) -DecimalFloatSqrtTest:testSqrtDeployed(bytes32) (runs: 5118, μ: 2664432, ~: 2662108) -DecimalFloatSubTest:testSubDeployed(bytes32,bytes32) (runs: 5118, μ: 2657477, ~: 2657499) -DecimalFloatToFixedDecimalLosslessTest:testToFixedDecimalLosslessDeployed(bytes32,uint8) (runs: 5118, μ: 2654482, ~: 2654361) -DecimalFloatToFixedDecimalLossyTest:testToFixedDecimalLossyDeployed(bytes32,uint8) (runs: 5118, μ: 2654617, ~: 2654890) -LibDecimalFloatAbsTest:testAbsMinValue(int32) (runs: 5117, μ: 5121, ~: 5121) -LibDecimalFloatAbsTest:testAbsNegative(int256,int32) (runs: 5118, μ: 10475, ~: 10702) -LibDecimalFloatAbsTest:testAbsNonNegative(int256,int32) (runs: 5118, μ: 9640, ~: 9392) +DecimalFloatAbsTest:testAbsDeployed(bytes32) (runs: 5096, μ: 2652661, ~: 2652603) +DecimalFloatAddTest:testAddDeployed(bytes32,bytes32) (runs: 5096, μ: 2656720, ~: 2656799) +DecimalFloatCeilTest:testCeilDeployed(bytes32) (runs: 5096, μ: 2652688, ~: 2652316) +DecimalFloatConstantsTest:testEDeployed() (gas: 2651846) +DecimalFloatConstantsTest:testMaxNegativeValueDeployed() (gas: 2651878) +DecimalFloatConstantsTest:testMaxPositiveValueDeployed() (gas: 2651836) +DecimalFloatConstantsTest:testMinNegativeValueDeployed() (gas: 2651811) +DecimalFloatConstantsTest:testMinPositiveValueDeployed() (gas: 2651790) +DecimalFloatDivTest:testDivDeployed(bytes32,bytes32) (runs: 5096, μ: 2657728, ~: 2657788) +DecimalFloatEqTest:testEqDeployed(bytes32,bytes32) (runs: 5096, μ: 2653046, ~: 2652971) +DecimalFloatFloorTest:testFloorDeployed(bytes32) (runs: 5096, μ: 2652498, ~: 2652314) +DecimalFloatFormatTest:testFormatDeployed(bytes32) (runs: 5096, μ: 2656671, ~: 2656507) +DecimalFloatFracTest:testFracDeployed(bytes32) (runs: 5096, μ: 2652890, ~: 2652874) +DecimalFloatFromFixedDecimalLosslessTest:testFromFixedDecimalLosslessDeployed(uint256,uint8) (runs: 5096, μ: 2653444, ~: 2653378) +DecimalFloatFromFixedDecimalLossyTest:testFromFixedDecimalLossyDeployed(uint256,uint8) (runs: 5096, μ: 2653931, ~: 2653848) +DecimalFloatGtTest:testGtDeployed(bytes32,bytes32) (runs: 5096, μ: 2652988, ~: 2652913) +DecimalFloatGteTest:testGteDeployed(bytes32,bytes32) (runs: 5096, μ: 2652973, ~: 2652899) +DecimalFloatInvTest:testInvDeployed(bytes32) (runs: 5096, μ: 2656563, ~: 2656593) +DecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5096, μ: 2652156, ~: 2652156) +DecimalFloatLtTest:testLtDeployed(bytes32,bytes32) (runs: 5096, μ: 2652965, ~: 2652890) +DecimalFloatLteTest:testLteDeployed(bytes32,bytes32) (runs: 5096, μ: 2653018, ~: 2652943) +DecimalFloatMaxTest:testMaxDeployed(bytes32,bytes32) (runs: 5096, μ: 2653027, ~: 2652965) +DecimalFloatMinTest:testMinDeployed(bytes32,bytes32) (runs: 5096, μ: 2653047, ~: 2652985) +DecimalFloatMinusTest:testMinusDeployed(bytes32) (runs: 5096, μ: 2652761, ~: 2652761) +DecimalFloatMulTest:testMulDeployed(bytes32,bytes32) (runs: 5096, μ: 2654861, ~: 2655921) +DecimalFloatPackLosslessTest:testPackDeployed(int224,int32) (runs: 5096, μ: 158769, ~: 158769) +DecimalFloatParseTest:testParseDeployed(string) (runs: 5096, μ: 2655393, ~: 2655262) +DecimalFloatPowTest:testPowDeployed(bytes32,bytes32) (runs: 5096, μ: 2664724, ~: 2660994) +DecimalFloatSqrtTest:testSqrtDeployed(bytes32) (runs: 5096, μ: 2663992, ~: 2661708) +DecimalFloatSubTest:testSubDeployed(bytes32,bytes32) (runs: 5096, μ: 2657069, ~: 2657099) +DecimalFloatToFixedDecimalLosslessTest:testToFixedDecimalLosslessDeployed(bytes32,uint8) (runs: 5096, μ: 2654077, ~: 2653961) +DecimalFloatToFixedDecimalLossyTest:testToFixedDecimalLossyDeployed(bytes32,uint8) (runs: 5096, μ: 2654222, ~: 2654490) +LibDecimalFloatAbsTest:testAbsMinValue(int32) (runs: 5096, μ: 5121, ~: 5121) +LibDecimalFloatAbsTest:testAbsNegative(int256,int32) (runs: 5096, μ: 10475, ~: 10702) +LibDecimalFloatAbsTest:testAbsNonNegative(int256,int32) (runs: 5096, μ: 9641, ~: 9392) LibDecimalFloatCeilTest:testCeilExamples() (gas: 30794) -LibDecimalFloatCeilTest:testCeilInRange(int224,int256) (runs: 5118, μ: 11042, ~: 10713) -LibDecimalFloatCeilTest:testCeilLessThanMin(int224,int256) (runs: 5118, μ: 10060, ~: 9820) -LibDecimalFloatCeilTest:testCeilNonNegative(int224,int256) (runs: 5118, μ: 8961, ~: 9212) -LibDecimalFloatCeilTest:testCeilNotReverts(bytes32) (runs: 5118, μ: 598, ~: 411) -LibDecimalFloatCeilTest:testCeilZero(int32) (runs: 5118, μ: 5438, ~: 5438) +LibDecimalFloatCeilTest:testCeilInRange(int224,int256) (runs: 5096, μ: 11040, ~: 10713) +LibDecimalFloatCeilTest:testCeilLessThanMin(int224,int256) (runs: 5096, μ: 10059, ~: 9820) +LibDecimalFloatCeilTest:testCeilNonNegative(int224,int256) (runs: 5096, μ: 8961, ~: 9212) +LibDecimalFloatCeilTest:testCeilNotReverts(bytes32) (runs: 5096, μ: 598, ~: 411) +LibDecimalFloatCeilTest:testCeilZero(int32) (runs: 5096, μ: 5438, ~: 5438) LibDecimalFloatConstantsTest:testFloatE() (gas: 3357) LibDecimalFloatConstantsTest:testFloatHalf() (gas: 3336) LibDecimalFloatConstantsTest:testFloatMaxNegativeValue() (gas: 3379) -LibDecimalFloatConstantsTest:testFloatMaxNegativeValueIsMax(bytes32) (runs: 5118, μ: 4488, ~: 4594) +LibDecimalFloatConstantsTest:testFloatMaxNegativeValueIsMax(bytes32) (runs: 5096, μ: 4488, ~: 4594) LibDecimalFloatConstantsTest:testFloatMaxPositiveValue() (gas: 3335) -LibDecimalFloatConstantsTest:testFloatMaxPositiveValueIsMax(bytes32) (runs: 5118, μ: 3545, ~: 3586) +LibDecimalFloatConstantsTest:testFloatMaxPositiveValueIsMax(bytes32) (runs: 5096, μ: 3545, ~: 3586) LibDecimalFloatConstantsTest:testFloatMinNegativeValue() (gas: 3335) -LibDecimalFloatConstantsTest:testFloatMinNegativeValueIsMin(bytes32) (runs: 5118, μ: 3496, ~: 3457) +LibDecimalFloatConstantsTest:testFloatMinNegativeValueIsMin(bytes32) (runs: 5096, μ: 3496, ~: 3457) LibDecimalFloatConstantsTest:testFloatMinPositiveValue() (gas: 3357) -LibDecimalFloatConstantsTest:testFloatMinPositiveValueIsMin(bytes32) (runs: 5118, μ: 4938, ~: 4870) +LibDecimalFloatConstantsTest:testFloatMinPositiveValueIsMin(bytes32) (runs: 5096, μ: 4938, ~: 4870) LibDecimalFloatConstantsTest:testFloatOne() (gas: 3358) LibDecimalFloatConstantsTest:testFloatTwo() (gas: 3380) LibDecimalFloatConstantsTest:testFloatZero() (gas: 3337) -LibDecimalFloatDecimalAddTest:testAddPacked(bytes32,bytes32) (runs: 5118, μ: 9761, ~: 9832) -LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessFail(uint256,uint8) (runs: 5113, μ: 9615, ~: 9663) -LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessMem(uint256,uint8) (runs: 5118, μ: 8130, ~: 8048) -LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessPass(uint256,uint8) (runs: 5118, μ: 7452, ~: 7424) +LibDecimalFloatDecimalAddTest:testAddPacked(bytes32,bytes32) (runs: 5096, μ: 9762, ~: 9832) +LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessFail(uint256,uint8) (runs: 5096, μ: 9615, ~: 9663) +LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessMem(uint256,uint8) (runs: 5096, μ: 8130, ~: 8048) +LibDecimalFloatDecimalLosslessTest:testFromFixedDecimalLosslessPass(uint256,uint8) (runs: 5096, μ: 7452, ~: 7424) LibDecimalFloatDecimalLosslessTest:testToFixedDecimalLosslessFail() (gas: 4894) -LibDecimalFloatDecimalLosslessTest:testToFixedDecimalLosslessPacked(bytes32,uint8) (runs: 5118, μ: 6719, ~: 6161) -LibDecimalFloatDecimalLosslessTest:testToFixedDecimalLosslessPass(int256,int256,uint8) (runs: 5118, μ: 15805, ~: 15768) -LibDecimalFloatDecimalTest:testFixedDecimalRoundTripLossless(uint256,uint8) (runs: 5118, μ: 9274, ~: 9053) +LibDecimalFloatDecimalLosslessTest:testToFixedDecimalLosslessPacked(bytes32,uint8) (runs: 5096, μ: 6718, ~: 6161) +LibDecimalFloatDecimalLosslessTest:testToFixedDecimalLosslessPass(int256,int256,uint8) (runs: 5096, μ: 15805, ~: 15768) +LibDecimalFloatDecimalTest:testFixedDecimalRoundTripLossless(uint256,uint8) (runs: 5096, μ: 9274, ~: 9053) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyComplicated() (gas: 685958) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyNormalizedMax() (gas: 673506) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyNormalizedMaxPlusOne() (gas: 704362) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOne() (gas: 685936) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOneMillion() (gas: 685937) LibDecimalFloatDecimalTest:testFromFixedDecimalLossyOverflow() (gas: 715261) -LibDecimalFloatDecimalTest:testFromFixedDecimalLossyPacked(uint256,uint8) (runs: 5118, μ: 9460, ~: 9374) -LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateOne(uint256,uint8) (runs: 5118, μ: 5978, ~: 5937) -LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateZero(uint256,uint8) (runs: 5118, μ: 7307, ~: 5860) -LibDecimalFloatDecimalTest:testToFixedDecimalLosslessScaleUp(int256,int256,uint8) (runs: 5108, μ: 16005, ~: 15996) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyExponentOverflow(int256,int256,uint8) (runs: 5118, μ: 14963, ~: 14729) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyIdentity(int256,uint8) (runs: 5118, μ: 10151, ~: 9811) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyNegative(int256,int256,uint8) (runs: 5118, μ: 10825, ~: 11076) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyPacked(bytes32,uint8) (runs: 5118, μ: 6805, ~: 6905) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyScaleUpOverflow(int256,int256,uint8) (runs: 5106, μ: 15348, ~: 15612) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncate(int256,int256,uint8) (runs: 5118, μ: 14493, ~: 14212) +LibDecimalFloatDecimalTest:testFromFixedDecimalLossyPacked(uint256,uint8) (runs: 5096, μ: 9460, ~: 9374) +LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateOne(uint256,uint8) (runs: 5096, μ: 5978, ~: 5937) +LibDecimalFloatDecimalTest:testFromFixedDecimalLossyTruncateZero(uint256,uint8) (runs: 5096, μ: 7305, ~: 5860) +LibDecimalFloatDecimalTest:testToFixedDecimalLosslessScaleUp(int256,int256,uint8) (runs: 5096, μ: 16005, ~: 15996) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyExponentOverflow(int256,int256,uint8) (runs: 5096, μ: 14964, ~: 14729) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyIdentity(int256,uint8) (runs: 5096, μ: 10152, ~: 9811) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyNegative(int256,int256,uint8) (runs: 5096, μ: 10825, ~: 11076) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyPacked(bytes32,uint8) (runs: 5096, μ: 6804, ~: 6905) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyScaleUpOverflow(int256,int256,uint8) (runs: 5096, μ: 15348, ~: 15612) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncate(int256,int256,uint8) (runs: 5096, μ: 14493, ~: 14212) LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncateLossless() (gas: 14523) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyUnderflow(int256,int256,uint8) (runs: 5118, μ: 13739, ~: 13602) -LibDecimalFloatDecimalTest:testToFixedDecimalLossyZero(int256,uint8) (runs: 5118, μ: 4598, ~: 4598) -LibDecimalFloatDivTest:testDivPacked(bytes32,bytes32) (runs: 5118, μ: 10668, ~: 10745) -LibDecimalFloatEqTest:testEqPacked(bytes32,bytes32) (runs: 5118, μ: 5524, ~: 5450) -LibDecimalFloatEqTest:testEqXNotYExponents(bytes32,bytes32) (runs: 5118, μ: 4341, ~: 4234) -LibDecimalFloatEqTest:testEqZero(int32) (runs: 5118, μ: 5133, ~: 5133) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyUnderflow(int256,int256,uint8) (runs: 5096, μ: 13738, ~: 13602) +LibDecimalFloatDecimalTest:testToFixedDecimalLossyZero(int256,uint8) (runs: 5096, μ: 4598, ~: 4598) +LibDecimalFloatDivTest:testDivPacked(bytes32,bytes32) (runs: 5096, μ: 10658, ~: 10735) +LibDecimalFloatEqTest:testEqPacked(bytes32,bytes32) (runs: 5096, μ: 5524, ~: 5450) +LibDecimalFloatEqTest:testEqXNotYExponents(bytes32,bytes32) (runs: 5096, μ: 4341, ~: 4234) +LibDecimalFloatEqTest:testEqZero(int32) (runs: 5096, μ: 5133, ~: 5133) LibDecimalFloatFloorTest:testFloorExamples() (gas: 38387) LibDecimalFloatFloorTest:testFloorGas0() (gas: 960) LibDecimalFloatFloorTest:testFloorGasTiny() (gas: 881) LibDecimalFloatFloorTest:testFloorGasZero() (gas: 553) -LibDecimalFloatFloorTest:testFloorInRange(int224,int256) (runs: 5118, μ: 11032, ~: 11044) -LibDecimalFloatFloorTest:testFloorLessThanMin(int224,int256) (runs: 5118, μ: 10284, ~: 10293) -LibDecimalFloatFloorTest:testFloorNonNegative(int224,int256) (runs: 5118, μ: 9546, ~: 9806) -LibDecimalFloatFloorTest:testFloorNotReverts(bytes32) (runs: 5118, μ: 461, ~: 365) +LibDecimalFloatFloorTest:testFloorInRange(int224,int256) (runs: 5096, μ: 11032, ~: 11044) +LibDecimalFloatFloorTest:testFloorLessThanMin(int224,int256) (runs: 5096, μ: 10284, ~: 10293) +LibDecimalFloatFloorTest:testFloorNonNegative(int224,int256) (runs: 5096, μ: 9547, ~: 9806) +LibDecimalFloatFloorTest:testFloorNotReverts(bytes32) (runs: 5096, μ: 461, ~: 365) LibDecimalFloatFracTest:testFracExamples() (gas: 39135) LibDecimalFloatFracTest:testFracGas0() (gas: 960) LibDecimalFloatFracTest:testFracGasTiny() (gas: 836) LibDecimalFloatFracTest:testFracGasZero() (gas: 820) -LibDecimalFloatFracTest:testFracInRange(int224,int256) (runs: 5118, μ: 10847, ~: 10859) -LibDecimalFloatFracTest:testFracLessThanMin(int224,int256) (runs: 5118, μ: 10272, ~: 10280) -LibDecimalFloatFracTest:testFracNonNegative(int224,int256) (runs: 5118, μ: 9805, ~: 10066) -LibDecimalFloatFracTest:testFracNotReverts(bytes32) (runs: 5118, μ: 630, ~: 621) +LibDecimalFloatFracTest:testFracInRange(int224,int256) (runs: 5096, μ: 10847, ~: 10859) +LibDecimalFloatFracTest:testFracLessThanMin(int224,int256) (runs: 5096, μ: 10273, ~: 10280) +LibDecimalFloatFracTest:testFracNonNegative(int224,int256) (runs: 5096, μ: 9806, ~: 10066) +LibDecimalFloatFracTest:testFracNotReverts(bytes32) (runs: 5096, μ: 630, ~: 621) LibDecimalFloatGtTest:testGtGasAZero() (gas: 973) LibDecimalFloatGtTest:testGtGasBZero() (gas: 973) LibDecimalFloatGtTest:testGtGasBothZero() (gas: 751) LibDecimalFloatGtTest:testGtGasDifferentSigns() (gas: 974) LibDecimalFloatGtTest:testGtGasExponentDiffOverflow() (gas: 1143) -LibDecimalFloatGtTest:testGtOneEAny(bytes32) (runs: 5118, μ: 3494, ~: 3494) -LibDecimalFloatGtTest:testGtReference(int224,int32,int224,int32) (runs: 5118, μ: 8062, ~: 6272) -LibDecimalFloatGtTest:testGtX(int224,int32) (runs: 5118, μ: 3882, ~: 3882) -LibDecimalFloatGtTest:testGtXEAnyVsXEAny(int256,int32,int32) (runs: 5118, μ: 10592, ~: 10332) -LibDecimalFloatGtTest:testGtXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5118, μ: 11144, ~: 11349) -LibDecimalFloatGtTest:testGtXNotY(bytes32,bytes32) (runs: 5118, μ: 4341, ~: 4232) -LibDecimalFloatGtTest:testGtXPositiveYNegative(int256,int32,int256,int32) (runs: 5118, μ: 13764, ~: 13595) -LibDecimalFloatGtTest:testGtXPositiveYZero(int256,int32,int32) (runs: 5118, μ: 10273, ~: 10026) -LibDecimalFloatGtTest:testGtZero(int32,int32) (runs: 5118, μ: 4793, ~: 4793) +LibDecimalFloatGtTest:testGtOneEAny(bytes32) (runs: 5096, μ: 3494, ~: 3494) +LibDecimalFloatGtTest:testGtReference(int224,int32,int224,int32) (runs: 5096, μ: 8067, ~: 6285) +LibDecimalFloatGtTest:testGtX(int224,int32) (runs: 5096, μ: 3882, ~: 3882) +LibDecimalFloatGtTest:testGtXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 10592, ~: 10332) +LibDecimalFloatGtTest:testGtXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 11144, ~: 11349) +LibDecimalFloatGtTest:testGtXNotY(bytes32,bytes32) (runs: 5096, μ: 4341, ~: 4232) +LibDecimalFloatGtTest:testGtXPositiveYNegative(int256,int32,int256,int32) (runs: 5096, μ: 13764, ~: 13595) +LibDecimalFloatGtTest:testGtXPositiveYZero(int256,int32,int32) (runs: 5096, μ: 10273, ~: 10026) +LibDecimalFloatGtTest:testGtZero(int32,int32) (runs: 5096, μ: 4793, ~: 4793) LibDecimalFloatGteTest:testGteGasAZero() (gas: 976) LibDecimalFloatGteTest:testGteGasBZero() (gas: 1020) LibDecimalFloatGteTest:testGteGasBothZero() (gas: 753) LibDecimalFloatGteTest:testGteGasDifferentSigns() (gas: 996) LibDecimalFloatGteTest:testGteGasExponentDiffOverflow() (gas: 1102) -LibDecimalFloatGteTest:testGteOneEAny(bytes32) (runs: 5118, μ: 3494, ~: 3494) -LibDecimalFloatGteTest:testGteReference(int224,int32,int224,int32) (runs: 5118, μ: 8112, ~: 6318) -LibDecimalFloatGteTest:testGteX(int224,int32) (runs: 5118, μ: 3925, ~: 3925) -LibDecimalFloatGteTest:testGteXEAnyVsXEAny(int256,int32,int32) (runs: 5118, μ: 10621, ~: 10364) -LibDecimalFloatGteTest:testGteXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5118, μ: 11157, ~: 11361) -LibDecimalFloatGteTest:testGteXNotLtY(bytes32,bytes32) (runs: 5118, μ: 3947, ~: 3873) -LibDecimalFloatGteTest:testGteXPositiveYNegative(int256,int32,int256,int32) (runs: 5118, μ: 13794, ~: 13623) -LibDecimalFloatGteTest:testGteXPositiveYZero(int256,int32,int32) (runs: 5118, μ: 9550, ~: 9170) -LibDecimalFloatGteTest:testGteZero(int32,int32) (runs: 5118, μ: 4838, ~: 4838) +LibDecimalFloatGteTest:testGteOneEAny(bytes32) (runs: 5096, μ: 3494, ~: 3494) +LibDecimalFloatGteTest:testGteReference(int224,int32,int224,int32) (runs: 5096, μ: 8117, ~: 6344) +LibDecimalFloatGteTest:testGteX(int224,int32) (runs: 5096, μ: 3925, ~: 3925) +LibDecimalFloatGteTest:testGteXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 10622, ~: 10364) +LibDecimalFloatGteTest:testGteXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 11156, ~: 11361) +LibDecimalFloatGteTest:testGteXNotLtY(bytes32,bytes32) (runs: 5096, μ: 3947, ~: 3873) +LibDecimalFloatGteTest:testGteXPositiveYNegative(int256,int32,int256,int32) (runs: 5096, μ: 13794, ~: 13623) +LibDecimalFloatGteTest:testGteXPositiveYZero(int256,int32,int32) (runs: 5096, μ: 9551, ~: 9170) +LibDecimalFloatGteTest:testGteZero(int32,int32) (runs: 5096, μ: 4838, ~: 4838) LibDecimalFloatImplementationAddTest:testAdd123456789987654321() (gas: 4811) LibDecimalFloatImplementationAddTest:testAdd123456789e9987654321() (gas: 4861) -LibDecimalFloatImplementationAddTest:testAddNeverRevert(int256,int256,int256,int256) (runs: 5118, μ: 13100, ~: 13033) +LibDecimalFloatImplementationAddTest:testAddNeverRevert(int256,int256,int256,int256) (runs: 5096, μ: 13101, ~: 13034) LibDecimalFloatImplementationAddTest:testAddOneOneNotMaximized() (gas: 6148) LibDecimalFloatImplementationAddTest:testAddOneOnePreMaximized() (gas: 4300) LibDecimalFloatImplementationAddTest:testAddOneZero() (gas: 3666) -LibDecimalFloatImplementationAddTest:testAddSameExponent(int256,int256) (runs: 5111, μ: 6864, ~: 6935) +LibDecimalFloatImplementationAddTest:testAddSameExponent(int256,int256) (runs: 5096, μ: 6865, ~: 6935) LibDecimalFloatImplementationAddTest:testAddZero() (gas: 3665) -LibDecimalFloatImplementationAddTest:testAddZeroAnyExponent(int128) (runs: 5118, μ: 9293, ~: 9271) +LibDecimalFloatImplementationAddTest:testAddZeroAnyExponent(int128) (runs: 5096, μ: 9293, ~: 9271) LibDecimalFloatImplementationAddTest:testAddZeroOne() (gas: 3664) -LibDecimalFloatImplementationAddTest:testAddZeroToAnyNonZero(int256,int256,int256) (runs: 5117, μ: 13974, ~: 13948) +LibDecimalFloatImplementationAddTest:testAddZeroToAnyNonZero(int256,int256,int256) (runs: 5096, μ: 13974, ~: 13948) LibDecimalFloatImplementationAddTest:testAddingSmallToLargeReturnsLargeExamples() (gas: 92086) -LibDecimalFloatImplementationAddTest:testAddingSmallToLargeReturnsLargeFuzz(int256,int256,int256,int256) (runs: 5104, μ: 16980, ~: 16963) +LibDecimalFloatImplementationAddTest:testAddingSmallToLargeReturnsLargeFuzz(int256,int256,int256,int256) (runs: 5096, μ: 16980, ~: 16963) LibDecimalFloatImplementationAddTest:testGasAddOne() (gas: 1342) LibDecimalFloatImplementationAddTest:testGasAddZero() (gas: 360) -LibDecimalFloatImplementationAddTest:testOverflowChecks(int256,int256) (runs: 5118, μ: 3857, ~: 3843) +LibDecimalFloatImplementationAddTest:testOverflowChecks(int256,int256) (runs: 5096, μ: 3857, ~: 3843) LibDecimalFloatImplementationCharacteristicMantissaTest:testCharacteristicMantissaExamples() (gas: 30611) -LibDecimalFloatImplementationDivTest:testDiv1Over3() (gas: 6621) -LibDecimalFloatImplementationDivTest:testDiv1Over3Gas0() (gas: 1769) -LibDecimalFloatImplementationDivTest:testDiv1Over3Gas10() (gas: 14582) -LibDecimalFloatImplementationDivTest:testDiv1Over9Over1Over3() (gas: 12791) -LibDecimalFloatImplementationDivTest:testDiv1e18Over3() (gas: 6280) -LibDecimalFloatImplementationDivTest:testDivNegative1Over3() (gas: 6719) -LibDecimalFloatImplementationDivTest:testDivOOMs5and2() (gas: 5901) -LibDecimalFloatImplementationDivTest:testDivOOMsOverTen() (gas: 6591) -LibDecimalFloatImplementationDivTest:testDivTenOverOOMs() (gas: 6504) -LibDecimalFloatImplementationDivTest:testUnnormalizedThreesDiv0(int256,int256) (runs: 122, μ: 24551459, ~: 24551233) +LibDecimalFloatImplementationDivTest:testDiv1Over3() (gas: 6616) +LibDecimalFloatImplementationDivTest:testDiv1Over3Gas0() (gas: 1764) +LibDecimalFloatImplementationDivTest:testDiv1Over3Gas10() (gas: 14532) +LibDecimalFloatImplementationDivTest:testDiv1Over9Over1Over3() (gas: 12771) +LibDecimalFloatImplementationDivTest:testDiv1e18Over3() (gas: 6275) +LibDecimalFloatImplementationDivTest:testDivNegative1Over3() (gas: 6714) +LibDecimalFloatImplementationDivTest:testDivOOMs5and2() (gas: 5896) +LibDecimalFloatImplementationDivTest:testDivOOMsOverTen() (gas: 6586) +LibDecimalFloatImplementationDivTest:testDivTenOverOOMs() (gas: 6499) +LibDecimalFloatImplementationDivTest:testUnnormalizedThreesDiv0(int256,int256) (runs: 100, μ: 24521809, ~: 24521513) LibDecimalFloatImplementationEqTest:testEqGasAZero() (gas: 430) LibDecimalFloatImplementationEqTest:testEqGasBZero() (gas: 473) LibDecimalFloatImplementationEqTest:testEqGasBothZero() (gas: 450) LibDecimalFloatImplementationEqTest:testEqGasDifferentSigns() (gas: 482) LibDecimalFloatImplementationEqTest:testEqGasExponentDiffOverflow() (gas: 533) -LibDecimalFloatImplementationEqTest:testEqNotReverts(int256,int256,int256,int256) (runs: 5118, μ: 654, ~: 679) -LibDecimalFloatImplementationEqTest:testEqOneEAny(int256,int256) (runs: 5118, μ: 3416, ~: 3416) -LibDecimalFloatImplementationEqTest:testEqReference(int256,int256,int256,int256) (runs: 5118, μ: 9903, ~: 11446) -LibDecimalFloatImplementationEqTest:testEqX(int256) (runs: 5118, μ: 3392, ~: 3392) -LibDecimalFloatImplementationEqTest:testEqXEAnyVsXEAny(int256,int256,int256) (runs: 5116, μ: 4718, ~: 4714) -LibDecimalFloatImplementationEqTest:testEqXEqY(int256,int256,int256,int256) (runs: 5118, μ: 732, ~: 753) -LibDecimalFloatImplementationEqTest:testEqXNotY(int256,int256,int256,int256) (runs: 5118, μ: 3928, ~: 3953) -LibDecimalFloatImplementationEqTest:testEqZero(int256,int256) (runs: 5118, μ: 3440, ~: 3440) -LibDecimalFloatImplementationInvTest:testInvGas0() (gas: 1596) -LibDecimalFloatImplementationInvTest:testInvReference(int256,int256) (runs: 5116, μ: 13635, ~: 13595) -LibDecimalFloatImplementationInvTest:testInvSlowGas0() (gas: 1780) +LibDecimalFloatImplementationEqTest:testEqNotReverts(int256,int256,int256,int256) (runs: 5096, μ: 654, ~: 679) +LibDecimalFloatImplementationEqTest:testEqOneEAny(int256,int256) (runs: 5096, μ: 3416, ~: 3416) +LibDecimalFloatImplementationEqTest:testEqReference(int256,int256,int256,int256) (runs: 5096, μ: 9904, ~: 11446) +LibDecimalFloatImplementationEqTest:testEqX(int256) (runs: 5096, μ: 3392, ~: 3392) +LibDecimalFloatImplementationEqTest:testEqXEAnyVsXEAny(int256,int256,int256) (runs: 5096, μ: 4718, ~: 4714) +LibDecimalFloatImplementationEqTest:testEqXEqY(int256,int256,int256,int256) (runs: 5096, μ: 732, ~: 753) +LibDecimalFloatImplementationEqTest:testEqXNotY(int256,int256,int256,int256) (runs: 5096, μ: 3928, ~: 3953) +LibDecimalFloatImplementationEqTest:testEqZero(int256,int256) (runs: 5096, μ: 3440, ~: 3440) +LibDecimalFloatImplementationInvTest:testInvGas0() (gas: 1591) +LibDecimalFloatImplementationInvTest:testInvReference(int256,int256) (runs: 5096, μ: 13625, ~: 13585) +LibDecimalFloatImplementationInvTest:testInvSlowGas0() (gas: 1775) LibDecimalFloatImplementationLog10Test:testExactLogs() (gas: 1263178) LibDecimalFloatImplementationLog10Test:testExactLookupsLog10() (gas: 1280250) -LibDecimalFloatImplementationLog10Test:testInterpolatedLookups() (gas: 1260152) -LibDecimalFloatImplementationLog10Test:testSub1() (gas: 1258137) -LibDecimalFloatImplementationMaximizeTest:testMaximizedEverything(int256,int256) (runs: 5118, μ: 9478, ~: 9455) +LibDecimalFloatImplementationLog10Test:testInterpolatedLookups() (gas: 1260147) +LibDecimalFloatImplementationLog10Test:testSub1() (gas: 1258127) +LibDecimalFloatImplementationMaximizeTest:testMaximizedEverything(int256,int256) (runs: 5096, μ: 9478, ~: 9455) LibDecimalFloatImplementationMaximizeTest:testMaximizedExamples() (gas: 165819) -LibDecimalFloatImplementationMaximizeTest:testMaximizedIdempotent(int256,int256) (runs: 5118, μ: 9903, ~: 9868) -LibDecimalFloatImplementationMinusTest:testMinusIsSubZero(int256,int256,int256) (runs: 5118, μ: 12950, ~: 12929) +LibDecimalFloatImplementationMaximizeTest:testMaximizedIdempotent(int256,int256) (runs: 5096, μ: 9904, ~: 9868) +LibDecimalFloatImplementationMinusTest:testMinusIsSubZero(int256,int256,int256) (runs: 5096, μ: 12949, ~: 12929) LibDecimalFloatImplementationMulTest:testMul123456789987654321() (gas: 3676) -LibDecimalFloatImplementationMulTest:testMul123456789987654321WithExponents(int128,int128) (runs: 5118, μ: 13186, ~: 13270) +LibDecimalFloatImplementationMulTest:testMul123456789987654321WithExponents(int128,int128) (runs: 5096, μ: 13186, ~: 13270) LibDecimalFloatImplementationMulTest:testMul1e181e19() (gas: 3720) LibDecimalFloatImplementationMulTest:testMulGasOne() (gas: 382) LibDecimalFloatImplementationMulTest:testMulGasZero() (gas: 324) -LibDecimalFloatImplementationMulTest:testMulNotRevertAnyExpectation(int256,int256,int256,int256) (runs: 5118, μ: 13394, ~: 12563) +LibDecimalFloatImplementationMulTest:testMulNotRevertAnyExpectation(int256,int256,int256,int256) (runs: 5096, μ: 13394, ~: 12563) LibDecimalFloatImplementationMulTest:testMulOneOne() (gas: 3721) LibDecimalFloatImplementationMulTest:testMulOneZero() (gas: 3663) LibDecimalFloatImplementationMulTest:testMulZero0Exponent() (gas: 3620) -LibDecimalFloatImplementationMulTest:testMulZeroAnyExponent(int64,int64) (runs: 5118, μ: 3908, ~: 3908) +LibDecimalFloatImplementationMulTest:testMulZeroAnyExponent(int64,int64) (runs: 5096, μ: 3908, ~: 3908) LibDecimalFloatImplementationMulTest:testMulZeroOne() (gas: 3642) LibDecimalFloatImplementationNormalizeTest:testExamples() (gas: 160899) -LibDecimalFloatImplementationNormalizeTest:testIdempotent(int256,int256) (runs: 5118, μ: 9875, ~: 9808) -LibDecimalFloatImplementationNormalizeTest:testIsNormalizedReference(int256,int256) (runs: 5118, μ: 3533, ~: 3539) -LibDecimalFloatImplementationNormalizeTest:testNormalized(int256,int256) (runs: 5118, μ: 9415, ~: 9348) -LibDecimalFloatImplementationPow10Test:testExactLookupsPow10() (gas: 1282682) +LibDecimalFloatImplementationNormalizeTest:testIdempotent(int256,int256) (runs: 5096, μ: 9875, ~: 9808) +LibDecimalFloatImplementationNormalizeTest:testIsNormalizedReference(int256,int256) (runs: 5096, μ: 3533, ~: 3539) +LibDecimalFloatImplementationNormalizeTest:testNormalized(int256,int256) (runs: 5096, μ: 9415, ~: 9348) +LibDecimalFloatImplementationPow10Test:testExactLookupsPow10() (gas: 1282677) LibDecimalFloatImplementationPow10Test:testExactPows() (gas: 1260107) -LibDecimalFloatImplementationPow10Test:testInterpolatedLookupsPower() (gas: 1283525) -LibDecimalFloatImplementationPow10Test:testNoRevert(int224,int32) (runs: 5108, μ: 1259251, ~: 1260162) -LibDecimalFloatImplementationSubTest:testSubIsAdd(int256,int256,int256,int256) (runs: 5118, μ: 15800, ~: 15832) -LibDecimalFloatImplementationSubTest:testSubMinSignedValue(int256,int256,int256) (runs: 5118, μ: 14990, ~: 14932) +LibDecimalFloatImplementationPow10Test:testInterpolatedLookupsPower() (gas: 1283510) +LibDecimalFloatImplementationPow10Test:testNoRevert(int224,int32) (runs: 5096, μ: 1259240, ~: 1260152) +LibDecimalFloatImplementationSubTest:testSubIsAdd(int256,int256,int256,int256) (runs: 5096, μ: 15801, ~: 15834) +LibDecimalFloatImplementationSubTest:testSubMinSignedValue(int256,int256,int256) (runs: 5096, μ: 14990, ~: 14932) LibDecimalFloatImplementationSubTest:testSubOneFromMax() (gas: 6517) -LibDecimalFloatImplementationSubTest:testSubSelf(int224,int32) (runs: 5118, μ: 5509, ~: 5620) +LibDecimalFloatImplementationSubTest:testSubSelf(int224,int32) (runs: 5096, μ: 5509, ~: 5620) LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentExamples() (gas: 13429) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerExponentOverflowRescaleRevert(int256,int256,int256) (runs: 5104, μ: 14426, ~: 14395) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerExponentVeryLargeDiffRevert(int256,int256,int256) (runs: 5118, μ: 13307, ~: 13527) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerTargetExponentNoRevert(int256,int256,int256) (runs: 5118, μ: 11668, ~: 11718) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentSameExponentNoop(int256,int256) (runs: 5118, μ: 3676, ~: 3676) -LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentSmallerExponentNoRevert(int256,int256,int256) (runs: 5110, μ: 13874, ~: 13665) -LibDecimalFloatInvTest:testInvMem(bytes32) (runs: 5118, μ: 9670, ~: 9726) -LibDecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5118, μ: 3899, ~: 3899) -LibDecimalFloatIsZeroTest:testIsZeroEqZero(bytes32) (runs: 5118, μ: 3527, ~: 3527) -LibDecimalFloatIsZeroTest:testIsZeroExamples(int32) (runs: 5118, μ: 4477, ~: 4477) -LibDecimalFloatIsZeroTest:testNotIsZero(int224,int32) (runs: 5116, μ: 3896, ~: 3896) -LibDecimalFloatLog10Test:testLog10Packed(bytes32) (runs: 5118, μ: 1652204, ~: 1270767) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerExponentOverflowRescaleRevert(int256,int256,int256) (runs: 5096, μ: 14426, ~: 14395) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerExponentVeryLargeDiffRevert(int256,int256,int256) (runs: 5096, μ: 13307, ~: 13527) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerTargetExponentNoRevert(int256,int256,int256) (runs: 5096, μ: 11669, ~: 11718) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentSameExponentNoop(int256,int256) (runs: 5096, μ: 3676, ~: 3676) +LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentSmallerExponentNoRevert(int256,int256,int256) (runs: 5096, μ: 13874, ~: 13665) +LibDecimalFloatInvTest:testInvMem(bytes32) (runs: 5096, μ: 9660, ~: 9716) +LibDecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5096, μ: 3899, ~: 3899) +LibDecimalFloatIsZeroTest:testIsZeroEqZero(bytes32) (runs: 5096, μ: 3527, ~: 3527) +LibDecimalFloatIsZeroTest:testIsZeroExamples(int32) (runs: 5096, μ: 4477, ~: 4477) +LibDecimalFloatIsZeroTest:testNotIsZero(int224,int32) (runs: 5096, μ: 3896, ~: 3896) +LibDecimalFloatLog10Test:testLog10Packed(bytes32) (runs: 5096, μ: 1653385, ~: 1270757) LibDecimalFloatLtTest:testLtExamples() (gas: 3994) LibDecimalFloatLtTest:testLtGasAZero() (gas: 946) LibDecimalFloatLtTest:testLtGasBZero() (gas: 1012) LibDecimalFloatLtTest:testLtGasBothZero() (gas: 969) LibDecimalFloatLtTest:testLtGasDifferentSigns() (gas: 969) LibDecimalFloatLtTest:testLtGasExponentDiffOverflow() (gas: 1053) -LibDecimalFloatLtTest:testLtNegativeVsPositive(int256,int32,int256,int32) (runs: 5118, μ: 13749, ~: 13593) -LibDecimalFloatLtTest:testLtNegativeVsZero(int256,int32,int32) (runs: 5118, μ: 10790, ~: 11008) -LibDecimalFloatLtTest:testLtOneEAny(int224,int32) (runs: 5118, μ: 3905, ~: 3905) -LibDecimalFloatLtTest:testLtReference(bytes32,bytes32) (runs: 5118, μ: 4696, ~: 4998) -LibDecimalFloatLtTest:testLtVsEqualVsGt(bytes32,bytes32) (runs: 5118, μ: 4323, ~: 4210) -LibDecimalFloatLtTest:testLtX(int224) (runs: 5118, μ: 3798, ~: 3798) -LibDecimalFloatLtTest:testLtXEAnyVsXEAny(int256,int32,int32) (runs: 5118, μ: 10557, ~: 10297) -LibDecimalFloatLtTest:testLtXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5118, μ: 11154, ~: 11359) -LibDecimalFloatLtTest:testLtZero(int32,int32) (runs: 5118, μ: 4171, ~: 4171) +LibDecimalFloatLtTest:testLtNegativeVsPositive(int256,int32,int256,int32) (runs: 5096, μ: 13750, ~: 13593) +LibDecimalFloatLtTest:testLtNegativeVsZero(int256,int32,int32) (runs: 5096, μ: 10790, ~: 11008) +LibDecimalFloatLtTest:testLtOneEAny(int224,int32) (runs: 5096, μ: 3905, ~: 3905) +LibDecimalFloatLtTest:testLtReference(bytes32,bytes32) (runs: 5096, μ: 4697, ~: 4998) +LibDecimalFloatLtTest:testLtVsEqualVsGt(bytes32,bytes32) (runs: 5096, μ: 4323, ~: 4210) +LibDecimalFloatLtTest:testLtX(int224) (runs: 5096, μ: 3798, ~: 3798) +LibDecimalFloatLtTest:testLtXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 10557, ~: 10297) +LibDecimalFloatLtTest:testLtXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 11153, ~: 11359) +LibDecimalFloatLtTest:testLtZero(int32,int32) (runs: 5096, μ: 4171, ~: 4171) LibDecimalFloatLteTest:testLteGasAZero() (gas: 997) LibDecimalFloatLteTest:testLteGasBZero() (gas: 999) LibDecimalFloatLteTest:testLteGasBothZero() (gas: 753) LibDecimalFloatLteTest:testLteGasDifferentSigns() (gas: 976) LibDecimalFloatLteTest:testLteGasExponentDiffOverflow() (gas: 1082) -LibDecimalFloatLteTest:testLteOneEAny(bytes32) (runs: 5118, μ: 3493, ~: 3493) -LibDecimalFloatLteTest:testLteReference(int224,int32,int224,int32) (runs: 5118, μ: 8107, ~: 6315) -LibDecimalFloatLteTest:testLteX(int224,int32) (runs: 5118, μ: 3904, ~: 3904) -LibDecimalFloatLteTest:testLteXEAnyVsXEAny(int256,int32,int32) (runs: 5118, μ: 10582, ~: 10321) -LibDecimalFloatLteTest:testLteXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5118, μ: 11177, ~: 11383) -LibDecimalFloatLteTest:testLteXNotLtY(bytes32,bytes32) (runs: 5118, μ: 3882, ~: 3807) -LibDecimalFloatLteTest:testLteXPositiveYNegative(int256,int32,int256,int32) (runs: 5118, μ: 13102, ~: 12931) -LibDecimalFloatLteTest:testLteXPositiveYZero(int256,int32,int32) (runs: 5118, μ: 9574, ~: 9191) -LibDecimalFloatLteTest:testLteZero(int32,int32) (runs: 5118, μ: 4816, ~: 4816) -LibDecimalFloatMaxTest:testMaxX(bytes32) (runs: 5118, μ: 4246, ~: 4246) -LibDecimalFloatMaxTest:testMaxXY(bytes32,bytes32) (runs: 5118, μ: 4689, ~: 4613) -LibDecimalFloatMaxTest:testMaxXYEqual(bytes32) (runs: 5118, μ: 5272, ~: 5272) -LibDecimalFloatMaxTest:testMaxXYGreater(bytes32,bytes32) (runs: 5109, μ: 6129, ~: 6016) -LibDecimalFloatMaxTest:testMaxXYLess(bytes32,bytes32) (runs: 5105, μ: 6141, ~: 6027) -LibDecimalFloatMinTest:testMinX(bytes32) (runs: 5118, μ: 4268, ~: 4268) -LibDecimalFloatMinTest:testMinXY(bytes32,bytes32) (runs: 5118, μ: 4689, ~: 4613) -LibDecimalFloatMinTest:testMinXYEqual(bytes32) (runs: 5118, μ: 5292, ~: 5292) -LibDecimalFloatMinTest:testMinXYGreater(bytes32,bytes32) (runs: 5110, μ: 6074, ~: 5961) -LibDecimalFloatMinTest:testMinXYLess(bytes32,bytes32) (runs: 5104, μ: 6087, ~: 5972) -LibDecimalFloatMinusTest:testMinusPacked(bytes32) (runs: 5118, μ: 5550, ~: 5550) -LibDecimalFloatMixedTest:testDiv1Over3Mixed() (gas: 9513) -LibDecimalFloatMulTest:testMulPacked(bytes32,bytes32) (runs: 5118, μ: 7889, ~: 8837) -LibDecimalFloatPackTest:testPartsRoundTrip(int224,int32) (runs: 5118, μ: 5352, ~: 5352) -LibDecimalFloatPow10Test:testPow10Packed(bytes32) (runs: 5118, μ: 1648539, ~: 1258791) -LibDecimalFloatPowTest:testNegativePowError(bytes32,bytes32) (runs: 5118, μ: 1248480, ~: 1248447) -LibDecimalFloatPowTest:testPowAZero(int32,bytes32) (runs: 5110, μ: 1246471, ~: 1246471) -LibDecimalFloatPowTest:testPowAZeroNegative(bytes32) (runs: 5098, μ: 1246870, ~: 1246870) -LibDecimalFloatPowTest:testPowBZero(bytes32,int32) (runs: 5118, μ: 1246058, ~: 1246058) -LibDecimalFloatPowTest:testPows() (gas: 1312710) -LibDecimalFloatPowTest:testRoundTripFuzzPow(bytes32,bytes32) (runs: 5118, μ: 1261607, ~: 1258764) -LibDecimalFloatPowTest:testRoundTripSimple() (gas: 1509162) -LibDecimalFloatSqrtTest:testRoundTripFuzzSqrt(int224,int32) (runs: 5118, μ: 1293488, ~: 1293796) -LibDecimalFloatSqrtTest:testSqrt() (gas: 1293184) -LibDecimalFloatSqrtTest:testSqrtNegative(bytes32) (runs: 5118, μ: 1248100, ~: 1248059) -LibDecimalFloatSqrtTest:testSqrtRoundTrip() (gas: 1400335) -LibDecimalFloatSubTest:testSubPacked(bytes32,bytes32) (runs: 5118, μ: 9973, ~: 9995) +LibDecimalFloatLteTest:testLteOneEAny(bytes32) (runs: 5096, μ: 3493, ~: 3493) +LibDecimalFloatLteTest:testLteReference(int224,int32,int224,int32) (runs: 5096, μ: 8112, ~: 6341) +LibDecimalFloatLteTest:testLteX(int224,int32) (runs: 5096, μ: 3904, ~: 3904) +LibDecimalFloatLteTest:testLteXEAnyVsXEAny(int256,int32,int32) (runs: 5096, μ: 10582, ~: 10321) +LibDecimalFloatLteTest:testLteXEAnyVsXEAnyNegative(int256,int32,int32) (runs: 5096, μ: 11177, ~: 11383) +LibDecimalFloatLteTest:testLteXNotLtY(bytes32,bytes32) (runs: 5096, μ: 3882, ~: 3807) +LibDecimalFloatLteTest:testLteXPositiveYNegative(int256,int32,int256,int32) (runs: 5096, μ: 13103, ~: 12931) +LibDecimalFloatLteTest:testLteXPositiveYZero(int256,int32,int32) (runs: 5096, μ: 9575, ~: 9191) +LibDecimalFloatLteTest:testLteZero(int32,int32) (runs: 5096, μ: 4816, ~: 4816) +LibDecimalFloatMaxTest:testMaxX(bytes32) (runs: 5096, μ: 4246, ~: 4246) +LibDecimalFloatMaxTest:testMaxXY(bytes32,bytes32) (runs: 5096, μ: 4689, ~: 4613) +LibDecimalFloatMaxTest:testMaxXYEqual(bytes32) (runs: 5096, μ: 5272, ~: 5272) +LibDecimalFloatMaxTest:testMaxXYGreater(bytes32,bytes32) (runs: 5096, μ: 6129, ~: 6016) +LibDecimalFloatMaxTest:testMaxXYLess(bytes32,bytes32) (runs: 5096, μ: 6141, ~: 6027) +LibDecimalFloatMinTest:testMinX(bytes32) (runs: 5096, μ: 4268, ~: 4268) +LibDecimalFloatMinTest:testMinXY(bytes32,bytes32) (runs: 5096, μ: 4689, ~: 4613) +LibDecimalFloatMinTest:testMinXYEqual(bytes32) (runs: 5096, μ: 5292, ~: 5292) +LibDecimalFloatMinTest:testMinXYGreater(bytes32,bytes32) (runs: 5096, μ: 6074, ~: 5961) +LibDecimalFloatMinTest:testMinXYLess(bytes32,bytes32) (runs: 5096, μ: 6087, ~: 5972) +LibDecimalFloatMinusTest:testMinusPacked(bytes32) (runs: 5096, μ: 5550, ~: 5550) +LibDecimalFloatMixedTest:testDiv1Over3Mixed() (gas: 9508) +LibDecimalFloatMulTest:testMulPacked(bytes32,bytes32) (runs: 5096, μ: 7890, ~: 8837) +LibDecimalFloatPackTest:testPartsRoundTrip(int224,int32) (runs: 5096, μ: 5352, ~: 5352) +LibDecimalFloatPow10Test:testPow10Packed(bytes32) (runs: 5096, μ: 1644908, ~: 1258781) +LibDecimalFloatPowTest:testNegativePowError(bytes32,bytes32) (runs: 5096, μ: 1248480, ~: 1248447) +LibDecimalFloatPowTest:testPowAZero(int32,bytes32) (runs: 5096, μ: 1246471, ~: 1246471) +LibDecimalFloatPowTest:testPowAZeroNegative(bytes32) (runs: 5096, μ: 1246870, ~: 1246870) +LibDecimalFloatPowTest:testPowBZero(bytes32,int32) (runs: 5096, μ: 1246058, ~: 1246058) +LibDecimalFloatPowTest:testPows() (gas: 1312675) +LibDecimalFloatPowTest:testRoundTripFuzzPow(bytes32,bytes32) (runs: 5096, μ: 1261508, ~: 1258747) +LibDecimalFloatPowTest:testRoundTripSimple() (gas: 1508957) +LibDecimalFloatSqrtTest:testRoundTripFuzzSqrt(int224,int32) (runs: 5096, μ: 1293487, ~: 1293761) +LibDecimalFloatSqrtTest:testSqrt() (gas: 1293174) +LibDecimalFloatSqrtTest:testSqrtNegative(bytes32) (runs: 5096, μ: 1248100, ~: 1248059) +LibDecimalFloatSqrtTest:testSqrtRoundTrip() (gas: 1400270) +LibDecimalFloatSubTest:testSubPacked(bytes32,bytes32) (runs: 5096, μ: 9974, ~: 9995) LibFormatDecimalFloatTest:testFormatDecimalExamples() (gas: 133439) -LibFormatDecimalFloatTest:testFormatDecimalRoundTrip(uint256) (runs: 5118, μ: 25209, ~: 20105) -LibFormatDecimalFloatTest:testFormatDecimalRoundTripNegative(int256) (runs: 5118, μ: 19675, ~: 21006) +LibFormatDecimalFloatTest:testFormatDecimalRoundTrip(uint256) (runs: 5096, μ: 25219, ~: 20105) +LibFormatDecimalFloatTest:testFormatDecimalRoundTripNegative(int256) (runs: 5096, μ: 19679, ~: 21006) LibLogTableBytesTest:testToBytesAntiLogTableDec() (gas: 159794) LibLogTableBytesTest:testToBytesAntiLogTableDecSmall() (gas: 162322) LibLogTableBytesTest:testToBytesLogTableDec() (gas: 143165) @@ -293,7 +293,7 @@ LibParseDecimalFloatTest:testParseLiteralDecimalFloatEDot() (gas: 4190) LibParseDecimalFloatTest:testParseLiteralDecimalFloatExponentRevert5() (gas: 4176) LibParseDecimalFloatTest:testParseLiteralDecimalFloatExponentRevert6() (gas: 4188) LibParseDecimalFloatTest:testParseLiteralDecimalFloatExponents() (gas: 402635) -LibParseDecimalFloatTest:testParseLiteralDecimalFloatFuzz(uint256,uint8,bool) (runs: 5118, μ: 45938, ~: 37394) +LibParseDecimalFloatTest:testParseLiteralDecimalFloatFuzz(uint256,uint8,bool) (runs: 5096, μ: 45910, ~: 37386) LibParseDecimalFloatTest:testParseLiteralDecimalFloatLeadingZeros() (gas: 59779) LibParseDecimalFloatTest:testParseLiteralDecimalFloatNegativeE() (gas: 6100) LibParseDecimalFloatTest:testParseLiteralDecimalFloatNegativeFrac() (gas: 5137) @@ -301,5 +301,5 @@ LibParseDecimalFloatTest:testParseLiteralDecimalFloatPrecisionRevert0() (gas: 27 LibParseDecimalFloatTest:testParseLiteralDecimalFloatPrecisionRevert1() (gas: 24801) LibParseDecimalFloatTest:testParseLiteralDecimalFloatSpecific() (gas: 22959) LibParseDecimalFloatTest:testParseLiteralDecimalFloatUnrelated() (gas: 50856) -LibParseDecimalFloatTest:testParsePacked(string) (runs: 5118, μ: 9787, ~: 9668) -TestDecimalFloatUnpackTest:testUnpackDeployed(bytes32) (runs: 5118, μ: 158422, ~: 158422) \ No newline at end of file +LibParseDecimalFloatTest:testParsePacked(string) (runs: 5096, μ: 9787, ~: 9668) +TestDecimalFloatUnpackTest:testUnpackDeployed(bytes32) (runs: 5096, μ: 158422, ~: 158422) \ No newline at end of file diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index 476bcbb0..6b5df7bd 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -223,13 +223,13 @@ library LibDecimalFloatImplementation { // 512 bits, but will subsequently always be reduced back down to // fit in 256 bits by the division of a denominator that is larger // than the scale up. - int256 scale = 1e76; + uint256 scale = 1e76; int256 adjustExponent = 76; - if (signedCoefficientB / scale == 0) { + if (signedCoefficientBAbs < scale) { scale = 1e75; adjustExponent = 75; } - uint256 signedCoefficientAbs = mulDiv(signedCoefficientAAbs, uint256(scale), signedCoefficientBAbs); + uint256 signedCoefficientAbs = mulDiv(signedCoefficientAAbs, scale, signedCoefficientBAbs); int256 signedCoefficient = (signedCoefficientA ^ signedCoefficientB) < 0 ? -int256(signedCoefficientAbs) : int256(signedCoefficientAbs); From 194e3df7fb552db60dcac7f9f86b8c8ddf5054ae Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 18 Aug 2025 16:47:52 +0400 Subject: [PATCH 10/16] early return on 0 numerator div --- .gas-snapshot | 122 +++++++++--------- .../LibDecimalFloatImplementation.sol | 6 +- 2 files changed, 65 insertions(+), 63 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 4f2003f6..086fc50b 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,35 +1,35 @@ -DecimalFloatAbsTest:testAbsDeployed(bytes32) (runs: 5096, μ: 2652661, ~: 2652603) -DecimalFloatAddTest:testAddDeployed(bytes32,bytes32) (runs: 5096, μ: 2656720, ~: 2656799) -DecimalFloatCeilTest:testCeilDeployed(bytes32) (runs: 5096, μ: 2652688, ~: 2652316) -DecimalFloatConstantsTest:testEDeployed() (gas: 2651846) -DecimalFloatConstantsTest:testMaxNegativeValueDeployed() (gas: 2651878) -DecimalFloatConstantsTest:testMaxPositiveValueDeployed() (gas: 2651836) -DecimalFloatConstantsTest:testMinNegativeValueDeployed() (gas: 2651811) -DecimalFloatConstantsTest:testMinPositiveValueDeployed() (gas: 2651790) -DecimalFloatDivTest:testDivDeployed(bytes32,bytes32) (runs: 5096, μ: 2657728, ~: 2657788) -DecimalFloatEqTest:testEqDeployed(bytes32,bytes32) (runs: 5096, μ: 2653046, ~: 2652971) -DecimalFloatFloorTest:testFloorDeployed(bytes32) (runs: 5096, μ: 2652498, ~: 2652314) -DecimalFloatFormatTest:testFormatDeployed(bytes32) (runs: 5096, μ: 2656671, ~: 2656507) -DecimalFloatFracTest:testFracDeployed(bytes32) (runs: 5096, μ: 2652890, ~: 2652874) -DecimalFloatFromFixedDecimalLosslessTest:testFromFixedDecimalLosslessDeployed(uint256,uint8) (runs: 5096, μ: 2653444, ~: 2653378) -DecimalFloatFromFixedDecimalLossyTest:testFromFixedDecimalLossyDeployed(uint256,uint8) (runs: 5096, μ: 2653931, ~: 2653848) -DecimalFloatGtTest:testGtDeployed(bytes32,bytes32) (runs: 5096, μ: 2652988, ~: 2652913) -DecimalFloatGteTest:testGteDeployed(bytes32,bytes32) (runs: 5096, μ: 2652973, ~: 2652899) -DecimalFloatInvTest:testInvDeployed(bytes32) (runs: 5096, μ: 2656563, ~: 2656593) -DecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5096, μ: 2652156, ~: 2652156) -DecimalFloatLtTest:testLtDeployed(bytes32,bytes32) (runs: 5096, μ: 2652965, ~: 2652890) -DecimalFloatLteTest:testLteDeployed(bytes32,bytes32) (runs: 5096, μ: 2653018, ~: 2652943) -DecimalFloatMaxTest:testMaxDeployed(bytes32,bytes32) (runs: 5096, μ: 2653027, ~: 2652965) -DecimalFloatMinTest:testMinDeployed(bytes32,bytes32) (runs: 5096, μ: 2653047, ~: 2652985) -DecimalFloatMinusTest:testMinusDeployed(bytes32) (runs: 5096, μ: 2652761, ~: 2652761) -DecimalFloatMulTest:testMulDeployed(bytes32,bytes32) (runs: 5096, μ: 2654861, ~: 2655921) +DecimalFloatAbsTest:testAbsDeployed(bytes32) (runs: 5096, μ: 2657875, ~: 2657817) +DecimalFloatAddTest:testAddDeployed(bytes32,bytes32) (runs: 5096, μ: 2661931, ~: 2662013) +DecimalFloatCeilTest:testCeilDeployed(bytes32) (runs: 5096, μ: 2657902, ~: 2657530) +DecimalFloatConstantsTest:testEDeployed() (gas: 2657060) +DecimalFloatConstantsTest:testMaxNegativeValueDeployed() (gas: 2657092) +DecimalFloatConstantsTest:testMaxPositiveValueDeployed() (gas: 2657050) +DecimalFloatConstantsTest:testMinNegativeValueDeployed() (gas: 2657025) +DecimalFloatConstantsTest:testMinPositiveValueDeployed() (gas: 2657004) +DecimalFloatDivTest:testDivDeployed(bytes32,bytes32) (runs: 5096, μ: 2662969, ~: 2663034) +DecimalFloatEqTest:testEqDeployed(bytes32,bytes32) (runs: 5096, μ: 2658260, ~: 2658185) +DecimalFloatFloorTest:testFloorDeployed(bytes32) (runs: 5096, μ: 2657712, ~: 2657528) +DecimalFloatFormatTest:testFormatDeployed(bytes32) (runs: 5096, μ: 2661880, ~: 2661721) +DecimalFloatFracTest:testFracDeployed(bytes32) (runs: 5096, μ: 2658104, ~: 2658088) +DecimalFloatFromFixedDecimalLosslessTest:testFromFixedDecimalLosslessDeployed(uint256,uint8) (runs: 5096, μ: 2658659, ~: 2658592) +DecimalFloatFromFixedDecimalLossyTest:testFromFixedDecimalLossyDeployed(uint256,uint8) (runs: 5096, μ: 2659145, ~: 2659062) +DecimalFloatGtTest:testGtDeployed(bytes32,bytes32) (runs: 5096, μ: 2658201, ~: 2658127) +DecimalFloatGteTest:testGteDeployed(bytes32,bytes32) (runs: 5096, μ: 2658187, ~: 2658113) +DecimalFloatInvTest:testInvDeployed(bytes32) (runs: 5096, μ: 2661791, ~: 2661828) +DecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5096, μ: 2657370, ~: 2657370) +DecimalFloatLtTest:testLtDeployed(bytes32,bytes32) (runs: 5096, μ: 2658178, ~: 2658104) +DecimalFloatLteTest:testLteDeployed(bytes32,bytes32) (runs: 5096, μ: 2658231, ~: 2658157) +DecimalFloatMaxTest:testMaxDeployed(bytes32,bytes32) (runs: 5096, μ: 2658240, ~: 2658179) +DecimalFloatMinTest:testMinDeployed(bytes32,bytes32) (runs: 5096, μ: 2658261, ~: 2658199) +DecimalFloatMinusTest:testMinusDeployed(bytes32) (runs: 5096, μ: 2657975, ~: 2657975) +DecimalFloatMulTest:testMulDeployed(bytes32,bytes32) (runs: 5096, μ: 2660075, ~: 2661135) DecimalFloatPackLosslessTest:testPackDeployed(int224,int32) (runs: 5096, μ: 158769, ~: 158769) -DecimalFloatParseTest:testParseDeployed(string) (runs: 5096, μ: 2655393, ~: 2655262) -DecimalFloatPowTest:testPowDeployed(bytes32,bytes32) (runs: 5096, μ: 2664724, ~: 2660994) -DecimalFloatSqrtTest:testSqrtDeployed(bytes32) (runs: 5096, μ: 2663992, ~: 2661708) -DecimalFloatSubTest:testSubDeployed(bytes32,bytes32) (runs: 5096, μ: 2657069, ~: 2657099) -DecimalFloatToFixedDecimalLosslessTest:testToFixedDecimalLosslessDeployed(bytes32,uint8) (runs: 5096, μ: 2654077, ~: 2653961) -DecimalFloatToFixedDecimalLossyTest:testToFixedDecimalLossyDeployed(bytes32,uint8) (runs: 5096, μ: 2654222, ~: 2654490) +DecimalFloatParseTest:testParseDeployed(string) (runs: 5096, μ: 2660608, ~: 2660477) +DecimalFloatPowTest:testPowDeployed(bytes32,bytes32) (runs: 5096, μ: 2669675, ~: 2666208) +DecimalFloatSqrtTest:testSqrtDeployed(bytes32) (runs: 5096, μ: 2669032, ~: 2666922) +DecimalFloatSubTest:testSubDeployed(bytes32,bytes32) (runs: 5096, μ: 2662292, ~: 2662313) +DecimalFloatToFixedDecimalLosslessTest:testToFixedDecimalLosslessDeployed(bytes32,uint8) (runs: 5096, μ: 2659274, ~: 2659175) +DecimalFloatToFixedDecimalLossyTest:testToFixedDecimalLossyDeployed(bytes32,uint8) (runs: 5096, μ: 2659415, ~: 2659704) LibDecimalFloatAbsTest:testAbsMinValue(int32) (runs: 5096, μ: 5121, ~: 5121) LibDecimalFloatAbsTest:testAbsNegative(int256,int32) (runs: 5096, μ: 10475, ~: 10702) LibDecimalFloatAbsTest:testAbsNonNegative(int256,int32) (runs: 5096, μ: 9641, ~: 9392) @@ -79,7 +79,7 @@ LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncate(int256,int256,uint8) LibDecimalFloatDecimalTest:testToFixedDecimalLossyTruncateLossless() (gas: 14523) LibDecimalFloatDecimalTest:testToFixedDecimalLossyUnderflow(int256,int256,uint8) (runs: 5096, μ: 13738, ~: 13602) LibDecimalFloatDecimalTest:testToFixedDecimalLossyZero(int256,uint8) (runs: 5096, μ: 4598, ~: 4598) -LibDecimalFloatDivTest:testDivPacked(bytes32,bytes32) (runs: 5096, μ: 10658, ~: 10735) +LibDecimalFloatDivTest:testDivPacked(bytes32,bytes32) (runs: 5096, μ: 10691, ~: 10757) LibDecimalFloatEqTest:testEqPacked(bytes32,bytes32) (runs: 5096, μ: 5524, ~: 5450) LibDecimalFloatEqTest:testEqXNotYExponents(bytes32,bytes32) (runs: 5096, μ: 4341, ~: 4234) LibDecimalFloatEqTest:testEqZero(int32) (runs: 5096, μ: 5133, ~: 5133) @@ -144,16 +144,16 @@ LibDecimalFloatImplementationAddTest:testGasAddOne() (gas: 1342) LibDecimalFloatImplementationAddTest:testGasAddZero() (gas: 360) LibDecimalFloatImplementationAddTest:testOverflowChecks(int256,int256) (runs: 5096, μ: 3857, ~: 3843) LibDecimalFloatImplementationCharacteristicMantissaTest:testCharacteristicMantissaExamples() (gas: 30611) -LibDecimalFloatImplementationDivTest:testDiv1Over3() (gas: 6616) -LibDecimalFloatImplementationDivTest:testDiv1Over3Gas0() (gas: 1764) -LibDecimalFloatImplementationDivTest:testDiv1Over3Gas10() (gas: 14532) -LibDecimalFloatImplementationDivTest:testDiv1Over9Over1Over3() (gas: 12771) -LibDecimalFloatImplementationDivTest:testDiv1e18Over3() (gas: 6275) -LibDecimalFloatImplementationDivTest:testDivNegative1Over3() (gas: 6714) -LibDecimalFloatImplementationDivTest:testDivOOMs5and2() (gas: 5896) -LibDecimalFloatImplementationDivTest:testDivOOMsOverTen() (gas: 6586) -LibDecimalFloatImplementationDivTest:testDivTenOverOOMs() (gas: 6499) -LibDecimalFloatImplementationDivTest:testUnnormalizedThreesDiv0(int256,int256) (runs: 100, μ: 24521809, ~: 24521513) +LibDecimalFloatImplementationDivTest:testDiv1Over3() (gas: 6627) +LibDecimalFloatImplementationDivTest:testDiv1Over3Gas0() (gas: 1775) +LibDecimalFloatImplementationDivTest:testDiv1Over3Gas10() (gas: 14642) +LibDecimalFloatImplementationDivTest:testDiv1Over9Over1Over3() (gas: 12815) +LibDecimalFloatImplementationDivTest:testDiv1e18Over3() (gas: 6286) +LibDecimalFloatImplementationDivTest:testDivNegative1Over3() (gas: 6741) +LibDecimalFloatImplementationDivTest:testDivOOMs5and2() (gas: 5907) +LibDecimalFloatImplementationDivTest:testDivOOMsOverTen() (gas: 6597) +LibDecimalFloatImplementationDivTest:testDivTenOverOOMs() (gas: 6510) +LibDecimalFloatImplementationDivTest:testUnnormalizedThreesDiv0(int256,int256) (runs: 100, μ: 24587009, ~: 24586663) LibDecimalFloatImplementationEqTest:testEqGasAZero() (gas: 430) LibDecimalFloatImplementationEqTest:testEqGasBZero() (gas: 473) LibDecimalFloatImplementationEqTest:testEqGasBothZero() (gas: 450) @@ -167,13 +167,13 @@ LibDecimalFloatImplementationEqTest:testEqXEAnyVsXEAny(int256,int256,int256) (ru LibDecimalFloatImplementationEqTest:testEqXEqY(int256,int256,int256,int256) (runs: 5096, μ: 732, ~: 753) LibDecimalFloatImplementationEqTest:testEqXNotY(int256,int256,int256,int256) (runs: 5096, μ: 3928, ~: 3953) LibDecimalFloatImplementationEqTest:testEqZero(int256,int256) (runs: 5096, μ: 3440, ~: 3440) -LibDecimalFloatImplementationInvTest:testInvGas0() (gas: 1591) -LibDecimalFloatImplementationInvTest:testInvReference(int256,int256) (runs: 5096, μ: 13625, ~: 13585) -LibDecimalFloatImplementationInvTest:testInvSlowGas0() (gas: 1775) +LibDecimalFloatImplementationInvTest:testInvGas0() (gas: 1602) +LibDecimalFloatImplementationInvTest:testInvReference(int256,int256) (runs: 5096, μ: 13646, ~: 13607) +LibDecimalFloatImplementationInvTest:testInvSlowGas0() (gas: 1786) LibDecimalFloatImplementationLog10Test:testExactLogs() (gas: 1263178) LibDecimalFloatImplementationLog10Test:testExactLookupsLog10() (gas: 1280250) -LibDecimalFloatImplementationLog10Test:testInterpolatedLookups() (gas: 1260147) -LibDecimalFloatImplementationLog10Test:testSub1() (gas: 1258127) +LibDecimalFloatImplementationLog10Test:testInterpolatedLookups() (gas: 1260157) +LibDecimalFloatImplementationLog10Test:testSub1() (gas: 1257848) LibDecimalFloatImplementationMaximizeTest:testMaximizedEverything(int256,int256) (runs: 5096, μ: 9478, ~: 9455) LibDecimalFloatImplementationMaximizeTest:testMaximizedExamples() (gas: 165819) LibDecimalFloatImplementationMaximizeTest:testMaximizedIdempotent(int256,int256) (runs: 5096, μ: 9904, ~: 9868) @@ -193,10 +193,10 @@ LibDecimalFloatImplementationNormalizeTest:testExamples() (gas: 160899) LibDecimalFloatImplementationNormalizeTest:testIdempotent(int256,int256) (runs: 5096, μ: 9875, ~: 9808) LibDecimalFloatImplementationNormalizeTest:testIsNormalizedReference(int256,int256) (runs: 5096, μ: 3533, ~: 3539) LibDecimalFloatImplementationNormalizeTest:testNormalized(int256,int256) (runs: 5096, μ: 9415, ~: 9348) -LibDecimalFloatImplementationPow10Test:testExactLookupsPow10() (gas: 1282677) +LibDecimalFloatImplementationPow10Test:testExactLookupsPow10() (gas: 1282687) LibDecimalFloatImplementationPow10Test:testExactPows() (gas: 1260107) -LibDecimalFloatImplementationPow10Test:testInterpolatedLookupsPower() (gas: 1283510) -LibDecimalFloatImplementationPow10Test:testNoRevert(int224,int32) (runs: 5096, μ: 1259240, ~: 1260152) +LibDecimalFloatImplementationPow10Test:testInterpolatedLookupsPower() (gas: 1283540) +LibDecimalFloatImplementationPow10Test:testNoRevert(int224,int32) (runs: 5096, μ: 1259162, ~: 1259873) LibDecimalFloatImplementationSubTest:testSubIsAdd(int256,int256,int256,int256) (runs: 5096, μ: 15801, ~: 15834) LibDecimalFloatImplementationSubTest:testSubMinSignedValue(int256,int256,int256) (runs: 5096, μ: 14990, ~: 14932) LibDecimalFloatImplementationSubTest:testSubOneFromMax() (gas: 6517) @@ -207,12 +207,12 @@ LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLarger LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentLargerTargetExponentNoRevert(int256,int256,int256) (runs: 5096, μ: 11669, ~: 11718) LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentSameExponentNoop(int256,int256) (runs: 5096, μ: 3676, ~: 3676) LibDecimalFloatImplementationWithTargetExponentTest:testWithTargetExponentSmallerExponentNoRevert(int256,int256,int256) (runs: 5096, μ: 13874, ~: 13665) -LibDecimalFloatInvTest:testInvMem(bytes32) (runs: 5096, μ: 9660, ~: 9716) +LibDecimalFloatInvTest:testInvMem(bytes32) (runs: 5096, μ: 9679, ~: 9738) LibDecimalFloatIsZeroTest:testIsZeroDeployed(bytes32) (runs: 5096, μ: 3899, ~: 3899) LibDecimalFloatIsZeroTest:testIsZeroEqZero(bytes32) (runs: 5096, μ: 3527, ~: 3527) LibDecimalFloatIsZeroTest:testIsZeroExamples(int32) (runs: 5096, μ: 4477, ~: 4477) LibDecimalFloatIsZeroTest:testNotIsZero(int224,int32) (runs: 5096, μ: 3896, ~: 3896) -LibDecimalFloatLog10Test:testLog10Packed(bytes32) (runs: 5096, μ: 1653385, ~: 1270757) +LibDecimalFloatLog10Test:testLog10Packed(bytes32) (runs: 5096, μ: 1650742, ~: 1270777) LibDecimalFloatLtTest:testLtExamples() (gas: 3994) LibDecimalFloatLtTest:testLtGasAZero() (gas: 946) LibDecimalFloatLtTest:testLtGasBZero() (gas: 1012) @@ -253,21 +253,21 @@ LibDecimalFloatMinTest:testMinXYEqual(bytes32) (runs: 5096, μ: 5292, ~: 5292) LibDecimalFloatMinTest:testMinXYGreater(bytes32,bytes32) (runs: 5096, μ: 6074, ~: 5961) LibDecimalFloatMinTest:testMinXYLess(bytes32,bytes32) (runs: 5096, μ: 6087, ~: 5972) LibDecimalFloatMinusTest:testMinusPacked(bytes32) (runs: 5096, μ: 5550, ~: 5550) -LibDecimalFloatMixedTest:testDiv1Over3Mixed() (gas: 9508) +LibDecimalFloatMixedTest:testDiv1Over3Mixed() (gas: 9518) LibDecimalFloatMulTest:testMulPacked(bytes32,bytes32) (runs: 5096, μ: 7890, ~: 8837) LibDecimalFloatPackTest:testPartsRoundTrip(int224,int32) (runs: 5096, μ: 5352, ~: 5352) -LibDecimalFloatPow10Test:testPow10Packed(bytes32) (runs: 5096, μ: 1644908, ~: 1258781) +LibDecimalFloatPow10Test:testPow10Packed(bytes32) (runs: 5096, μ: 1644472, ~: 1258201) LibDecimalFloatPowTest:testNegativePowError(bytes32,bytes32) (runs: 5096, μ: 1248480, ~: 1248447) LibDecimalFloatPowTest:testPowAZero(int32,bytes32) (runs: 5096, μ: 1246471, ~: 1246471) LibDecimalFloatPowTest:testPowAZeroNegative(bytes32) (runs: 5096, μ: 1246870, ~: 1246870) LibDecimalFloatPowTest:testPowBZero(bytes32,int32) (runs: 5096, μ: 1246058, ~: 1246058) -LibDecimalFloatPowTest:testPows() (gas: 1312675) -LibDecimalFloatPowTest:testRoundTripFuzzPow(bytes32,bytes32) (runs: 5096, μ: 1261508, ~: 1258747) -LibDecimalFloatPowTest:testRoundTripSimple() (gas: 1508957) -LibDecimalFloatSqrtTest:testRoundTripFuzzSqrt(int224,int32) (runs: 5096, μ: 1293487, ~: 1293761) -LibDecimalFloatSqrtTest:testSqrt() (gas: 1293174) -LibDecimalFloatSqrtTest:testSqrtNegative(bytes32) (runs: 5096, μ: 1248100, ~: 1248059) -LibDecimalFloatSqrtTest:testSqrtRoundTrip() (gas: 1400270) +LibDecimalFloatPowTest:testPows() (gas: 1312147) +LibDecimalFloatPowTest:testRoundTripFuzzPow(bytes32,bytes32) (runs: 5096, μ: 1261462, ~: 1258766) +LibDecimalFloatPowTest:testRoundTripSimple() (gas: 1508171) +LibDecimalFloatSqrtTest:testRoundTripFuzzSqrt(int224,int32) (runs: 5096, μ: 1293364, ~: 1293233) +LibDecimalFloatSqrtTest:testSqrt() (gas: 1292895) +LibDecimalFloatSqrtTest:testSqrtNegative(bytes32) (runs: 5096, μ: 1248099, ~: 1248059) +LibDecimalFloatSqrtTest:testSqrtRoundTrip() (gas: 1400101) LibDecimalFloatSubTest:testSubPacked(bytes32,bytes32) (runs: 5096, μ: 9974, ~: 9995) LibFormatDecimalFloatTest:testFormatDecimalExamples() (gas: 133439) LibFormatDecimalFloatTest:testFormatDecimalRoundTrip(uint256) (runs: 5096, μ: 25219, ~: 20105) diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index 6b5df7bd..262736b6 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -197,14 +197,16 @@ library LibDecimalFloatImplementation { // mulDiv only works with unsigned integers, so get the absolute // values of the coefficients. uint256 signedCoefficientAAbs; - if (signedCoefficientA < 0) { + if (signedCoefficientA > 0) { + signedCoefficientAAbs = uint256(signedCoefficientA); + } else if (signedCoefficientA < 0) { if (signedCoefficientA == type(int256).min) { signedCoefficientAAbs = uint256(type(int256).max) + 1; } else { signedCoefficientAAbs = uint256(-signedCoefficientA); } } else { - signedCoefficientAAbs = uint256(signedCoefficientA); + return (MAXIMIZED_ZERO_SIGNED_COEFFICIENT, MAXIMIZED_ZERO_EXPONENT); } uint256 signedCoefficientBAbs; if (signedCoefficientB < 0) { From c0eb5b09f4b31838a269971c1d7c1593ee8bc227 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 18 Aug 2025 17:11:35 +0400 Subject: [PATCH 11/16] checked exponents in div --- .../LibDecimalFloatImplementation.sol | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/lib/implementation/LibDecimalFloatImplementation.sol b/src/lib/implementation/LibDecimalFloatImplementation.sol index 262736b6..b0cd5c74 100644 --- a/src/lib/implementation/LibDecimalFloatImplementation.sol +++ b/src/lib/implementation/LibDecimalFloatImplementation.sol @@ -188,6 +188,10 @@ library LibDecimalFloatImplementation { pure returns (int256, int256) { + uint256 scale = 1e76; + int256 adjustExponent = 76; + int256 signedCoefficient; + unchecked { // Move both coefficients into the e75/e76 range, so that the result // of division will not cause a mulDiv overflow. @@ -225,19 +229,20 @@ library LibDecimalFloatImplementation { // 512 bits, but will subsequently always be reduced back down to // fit in 256 bits by the division of a denominator that is larger // than the scale up. - uint256 scale = 1e76; - int256 adjustExponent = 76; if (signedCoefficientBAbs < scale) { scale = 1e75; adjustExponent = 75; } uint256 signedCoefficientAbs = mulDiv(signedCoefficientAAbs, scale, signedCoefficientBAbs); - int256 signedCoefficient = (signedCoefficientA ^ signedCoefficientB) < 0 + signedCoefficient = (signedCoefficientA ^ signedCoefficientB) < 0 ? -int256(signedCoefficientAbs) : int256(signedCoefficientAbs); - int256 exponent = exponentA - exponentB - adjustExponent; - return (signedCoefficient, exponent); } + + // Keep the exponent calculation outside the unchecked block so that we + // don't silently under/overflow. + int256 exponent = exponentA - exponentB - adjustExponent; + return (signedCoefficient, exponent); } /// mulDiv as seen in Open Zeppelin, PRB Math, Solady, and other libraries. From a84957588c3c4d64c3564a5b3889100a848c88d8 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 18 Aug 2025 17:18:21 +0400 Subject: [PATCH 12/16] test inv 0 --- .../LibDecimalFloatImplementation.inv.t.sol | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/src/lib/implementation/LibDecimalFloatImplementation.inv.t.sol b/test/src/lib/implementation/LibDecimalFloatImplementation.inv.t.sol index 2a46baf5..b1a4be20 100644 --- a/test/src/lib/implementation/LibDecimalFloatImplementation.inv.t.sol +++ b/test/src/lib/implementation/LibDecimalFloatImplementation.inv.t.sol @@ -6,10 +6,16 @@ import {LibDecimalFloatSlow} from "test/lib/LibDecimalFloatSlow.sol"; import { LibDecimalFloatImplementation, EXPONENT_MIN, - EXPONENT_MAX + EXPONENT_MAX, + MulDivOverflow } from "src/lib/implementation/LibDecimalFloatImplementation.sol"; contract LibDecimalFloatImplementationInvTest is Test { + function invExternal(int256 signedCoefficient, int256 exponent) external pure returns (int256, int256) { + (signedCoefficient, exponent) = LibDecimalFloatImplementation.inv(signedCoefficient, exponent); + return (signedCoefficient, exponent); + } + /// Compare reference. function testInvReference(int256 signedCoefficient, int256 exponent) external pure { vm.assume(signedCoefficient != 0); @@ -33,4 +39,9 @@ contract LibDecimalFloatImplementationInvTest is Test { (int256 outputSignedCoefficient, int256 outputExponent) = LibDecimalFloatSlow.invSlow(3e37, -37); (outputSignedCoefficient, outputExponent); } + + function testInv0() external { + vm.expectRevert(abi.encodeWithSelector(MulDivOverflow.selector, 1e76, 1e75, 0)); + this.invExternal(0, 0); + } } From 2f8ec84330aef85c645ee4558ce2b0b654c1ef22 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 18 Aug 2025 18:33:54 +0400 Subject: [PATCH 13/16] fix tests --- crates/float/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/float/src/lib.rs b/crates/float/src/lib.rs index 6a835c05..80a06439 100644 --- a/crates/float/src/lib.rs +++ b/crates/float/src/lib.rs @@ -1368,7 +1368,9 @@ mod tests { let zero = Float::parse("0".to_string()).unwrap(); let err = (one / zero).unwrap_err(); - assert!(matches!(err, FloatError::Revert(_))); + dbg!(&err); + + assert!(matches!(err, FloatError::DecimalFloat(DecimalFloatErrors::MulDivOverflow(_)))); } #[test] From 3aa059007dfa5e01caf510dce7a728cc4895cca6 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 18 Aug 2025 18:39:09 +0400 Subject: [PATCH 14/16] fmt --- crates/float/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/float/src/lib.rs b/crates/float/src/lib.rs index 80a06439..9490643a 100644 --- a/crates/float/src/lib.rs +++ b/crates/float/src/lib.rs @@ -1370,7 +1370,10 @@ mod tests { dbg!(&err); - assert!(matches!(err, FloatError::DecimalFloat(DecimalFloatErrors::MulDivOverflow(_)))); + assert!(matches!( + err, + FloatError::DecimalFloat(DecimalFloatErrors::MulDivOverflow(_)) + )); } #[test] From 941e2a1620a2b1e395a93d5882b38f42f450982d Mon Sep 17 00:00:00 2001 From: David Meister Date: Wed, 20 Aug 2025 16:06:24 +0400 Subject: [PATCH 15/16] Update crates/float/src/lib.rs --- crates/float/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/float/src/lib.rs b/crates/float/src/lib.rs index 9490643a..1db18827 100644 --- a/crates/float/src/lib.rs +++ b/crates/float/src/lib.rs @@ -1368,7 +1368,6 @@ mod tests { let zero = Float::parse("0".to_string()).unwrap(); let err = (one / zero).unwrap_err(); - dbg!(&err); assert!(matches!( err, From b87ef83e03b40da2a4ee980d129ce665a914c7ec Mon Sep 17 00:00:00 2001 From: David Meister Date: Wed, 20 Aug 2025 16:06:49 +0400 Subject: [PATCH 16/16] Update crates/float/src/lib.rs --- crates/float/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/float/src/lib.rs b/crates/float/src/lib.rs index 1db18827..b88b69f6 100644 --- a/crates/float/src/lib.rs +++ b/crates/float/src/lib.rs @@ -1368,7 +1368,6 @@ mod tests { let zero = Float::parse("0".to_string()).unwrap(); let err = (one / zero).unwrap_err(); - assert!(matches!( err, FloatError::DecimalFloat(DecimalFloatErrors::MulDivOverflow(_))