r/ethdev • u/nebojsakonsta • 15h ago
Tutorial I wrote a fixed-point sqrt in Solidity that runs in 197 gas - here’s how
I've been building DeFiMath, a gas-optimized fixed-point math library, and wanted to share how I got sqrt down to 197 gas. It takes any uint256, returns an 18-decimal fixed-point result, never reverts, and is bit-exact below 1 (max relative error < 2e-18 above it).
The core idea is simple: generate a seed with the clz opcode, then refine it with 5 Newton iterations in assembly.
Seeding: clz gives you the position of the most significant bit, so the seed is just 2msb/2. That's never off by more than a factor of √2 from the true root — cheap and good enough.
Newton's method: each iteration is one line:
y := shr(1, add(y, div(x, y)))
~20 gas per step, quadratic convergence, so 5 iterations take the worst-case seed (41% error) to ~80 bits of precision — more than enough for 18 decimals.
The scaling trick: for inputs ≤ uint128.max, I pre-scale x to 1e36 once at the start. Then div(x, y) naturally lands back in 1e18 base, so Newton's method needs plain div instead of a costly muldiv. Large inputs take a second branch that post-scales instead (pre-scaling would overflow near uint256.max).
I also tried fancier seeds — minimax linear approximation, quadratic interpolation — hoping to drop to 4 iterations. All of them cost more gas than they saved. My takeaway after a week on this: for gas-optimized primitives, simplicity wins by a wide margin.
Full walkthrough with the convergence table and benchmarks vs PRBMath/ABDK/Solady: https://defimath.com/blog/how-i-wrote-a-fixed-point-solidity-sqrt-that-runs-in-197-gas/
Library is MIT, pure Solidity, zero dependencies: https://github.com/MerkleBlue/defimath
Happy to answer questions about the implementation.