sqrt

Math

Computes the principal square root of an 18-decimal fixed-point input.

Gas

245

Max abs. error

2.8e-16

Signature

solidity
function sqrt(uint256 x) internal pure returns (uint256 y)

Parameters

NameTypeDescription
xuint256Input in 18-decimal fixed-point format (1e18 = 1.0). Must satisfy x < 2⁸⁰·1e18 (~1.2e42).

Returns

NameTypeDescription
yuint256Square root √x in 18-decimal fixed-point format.

Behavior

  • Returns 0 when x == 0 (no revert).
  • Reverts with SqrtUpperBoundError() when the underlying value exceeds 2⁸⁰ (~1.2e24).
  • Uses the CLZ opcode (Osaka) for a near-optimal initial guess; see EIP-7939.
  • Pure assembly hot path; no external calls or storage.

How it works

Square root in fixed-point reduces to two well-known problems: getting a fast initial guess and converging quickly with Newton's iteration. DeFiMath does both in assembly. The CLZ opcode (introduced in EVM Osaka) gives us floor(log2(x)) for free, and from there an initial guess y₀ = 2^⌈bits/2⌉ lands within a factor of √2 (~1.41) of the true root — a one-bit error. Newton's iteration

y ← (y + x/y) / 2

then doubles the number of correct bits every step, so six iterations carry us from one correct bit to 64 — comfortably bit-exact at the 1e18 fixed-point scale.

To compute sqrt(v) · 1e18 we scale the input first: sqrt(x · 1e18) = sqrt(v · 1e36) = sqrt(v) · 1e18. So for inputs ≥ 1.0 we multiply by 1e18 once, run the iteration, and we're done. The 2⁸⁰ true-value cap keeps the scaled value x · 1e18 safely inside uint256.

For inputs below 1.0 we invert instead of scaling: compute sqrt(1e54 / x), then divide 1e36 by the result. This preserves bit precision — a naive sqrt(x · 1e18) for tiny x would land in too few high-order bits and lose accuracy. The whole hot path stays in unchecked Yul assembly with no branches inside Newton — ~245 gas, the cheapest sqrt of any on-chain library we've measured.

Example

solidity
import "defimath-lib/contracts/math/Math.sol";

uint256 x = 2e18;             // x = 2.0
uint256 y = DeFiMath.sqrt(x); // y ≈ 1.41421356e18