Skip to content

Conversation

@Vectorized
Copy link
Owner

@Vectorized Vectorized commented Jul 11, 2025

Description

Short version:

/// @dev Returns `sqrt(x * y)`. Also called the geometric mean.
function mulSqrt(uint256 x, uint256 y) internal pure returns (uint256 z) {
    if (x == y) return x;
    uint256 p = rawMul(x, y);
    if (y == rawDiv(p, x)) return sqrt(p);
    for (z = saturatingMul(rawAdd(sqrt(x), 1), rawAdd(sqrt(y), 1));; z = avg(z, p)) {
        if ((p = fullMulDivUnchecked(x, y, z)) >= z) break;
    }
}
[PASS] testMulSqrt() (gas: 287258)
[PASS] test__codesize() (gas: 62144)

Inlined version:

/// @dev Returns `sqrt(x * y)`. Also called the geometric mean.
function mulSqrt(uint256 x, uint256 y) internal pure returns (uint256 z) {
    if (x == y) return x; // Identity.
    uint256 p0 = rawMul(x, y); // Lower 256 bits of `x * y`.
    if (y == rawDiv(p0, x)) return sqrt(p0);
    z = saturatingMul(rawAdd(sqrt(x), 1), rawAdd(sqrt(y), 1)); // Initial over-estimate.
    /// @solidity memory-safe-assembly
    assembly {
        let mm := mulmod(x, y, not(0))
        let p1 := sub(mm, add(p0, lt(mm, p0))) // Upper 256 bits of `x * y`.
        // Babylonian with inlined `fullMulDiv`.
        for {} 1 {} {
            let t := and(z, sub(0, z))
            let r := mulmod(x, y, z)
            let d := div(z, t)
            let inv := xor(2, mul(3, d))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            let q :=
                mul(
                    or(mul(sub(p1, gt(r, p0)), add(div(sub(0, t), t), 1)), div(sub(p0, r), t)),
                    mul(sub(2, mul(d, inv)), inv)
                )
            if iszero(lt(q, z)) { break }
            z := add(and(z, q), shr(1, xor(z, q))) // Non-overflowing average.
        }
    }
}
[PASS] testMulSqrt() (gas: 262692)
[PASS] test__codesize() (gas: 62243)

Checklist

Ensure you completed all of the steps below before submitting your pull request:

  • Ran forge fmt?
  • Ran forge test?

Pull requests with an incomplete checklist will be thrown out.

@github-actions
Copy link

github-actions bot commented Jul 11, 2025

Gas Snapshot Comparison Report

Generated at commit : d74d21e, Compared to commit : ba711c9

Contract Name Test Name Main Gas PR Gas Diff
FixedPointMathLibTest testAbs() 679 701 22
testAvgEdgeCase() 470 448 -22
testAvgSigned() 901 923 22
testCbrt() 10328 10283 -45
testCbrtWadConverged() 2725 2716 -9
testCbrtWadDebug() 7339 7383 44
testCbrtWadMonotonicallyIncreasing() 4183 4227 44
testDist() 656 678 22
testDistEdgeCases() 526 570 44
testDivWad() 692 736 44
testDivWadUp() 2986 2964 -22
testDivWadUpEdgeCases() 451 450 -1
testDivWadUpZeroDenominatorReverts() 3982 3960 -22
testDivWadZeroDenominatorReverts() 4025 3963 -62
testFactorial() 99191 99190 -1
testFullMulDiv() 1128 1106 -22
testFullMulDivN() 874 896 22
testFullMulDivUnchecked() 1613 1635 22
testFullMulDivUpRevertsIfRoundedUpResultOverflowsCase1() 4512 4468 -44
testFullMulDivUpRevertsIfRoundedUpResultOverflowsCase2() 4556 4512 -44
testGcd() 4207 4229 22
testInvMod() 12915 12892 -23
testLambertW0WadKnownValues() 1685617 1685605 -12
testLambertW0WadMonoDebug() 770690 770668 -22
testLambertW0WadMonotonicallyIncreasing() 18416531 18416509 -22
testLambertW0WadRevertsForOutOfDomain() 58122 58144 22
testLambertW0WadWithinBounds() 122062 122084 22
testLerpUint() 6398 6442 44
testLnWad() 2054 2076 22
testLnWadBig() 2066 2088 22
testLnWadNegativeReverts() 6191 6257 66
testLnWadOverflowReverts() 4028 4051 23
testLnWadSmall() 2667 2708 41
testLog10() 76190 76212 22
testLog10Up() 4413 4435 22
testLog256() 22853 22809 -44
testLog256Up() 1294 1293 -1
testLog2Up() 297369 297346 -23
testMulDiv() 1890 1912 22
testMulDivEdgeCases() 741 763 22
testMulDivUp() 2169 2126 -43
testMulDivUpEdgeCases() 862 839 -23
testMulDivUpZeroDenominator() 4077 4056 -21
testMulDivZeroDenominatorReverts() 4055 4033 -22
testMulWad() 690 712 22
testMulWadEdgeCases() 754 709 -45
testMulWadUp() 757 779 22
testMulWadUpEdgeCases() 799 776 -23
testPackUnpackSci() 130063 130040 -23
testRPow() 3276 3298 22
testRPowOverflowReverts() 8168 8256 88
testSDivWad() 840 862 22
testSMulWad() 1053 1033 -20
testSMulWadEdgeCases() 1265 1287 22
testSaturatingAdd() 1774 1729 -45
testSaturatingMul() 1838 1837 -1
testSci() 1838614 1838658 44
testSqrt() 43842 45393 1551
testSqrtHashedSingle() 54610 54632 22
testSqrtWad() 7981 7937 -44
test__codesize() 49928 62144 12216
testMulSqrt() - 287258 -

@Vectorized Vectorized merged commit a096f4f into main Jul 14, 2025
13 checks passed
@Vectorized Vectorized deleted the mulsqrt branch July 14, 2025 10:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants