cbrt

Math

Computes cube root of x in 18-decimal fixed-point.

Avg. gas

340

Max abs. error

1.0e-16

when cbrt(x) < 1

Max rel. error

2.0e-13

when cbrt(x) ≥ 1

Signature

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

Parameters

NameTypeDescription
xuint256Input in 18-decimal fixed-point format (1e18 = 1.0). Any value in [0, uint256.max] accepted.

Returns

NameTypeDescription
yuint256Cube root ∛x in 18-decimal fixed-point format.

Bounds

BoundValue
Input domainFull uint256 domain — the function has no named bounds and accepts any input in [0, uint256.max]. The internal branch cutoff at type(uint128).max is an implementation detail, not a limit on callers.

Behavior

  • Returns 0 when x == 0 — handled by the algorithm's natural underflow via EVM's div(0, 0) = 0 semantic, no explicit guard.
  • Never reverts. Handles the full [0, uint256.max] range via a two-branch split at type(uint128).max.
  • Uses the CLZ opcode (Osaka) for a near-optimal initial guess; see Counting leading zeros in Solidity using CLZ opcode.
  • Pure assembly hot path; no external calls or storage.

How it works

Cube root follows the same recipe as sqrt— a CLZ-derived initial guess plus Newton's iteration. The cube-root Newton update is

y ← (2y + x/y²) / 3

which still has quadratic convergence: each step roughly doubles the number of correct bits. The CLZ-derived initial guess y₀ = 2^⌈bits/3⌉ lands within a factor of ∛2 (~1.26) of the true root — slightly tighter than sqrt's √2 start. Six iterations reach bit-exact precision at the FP18 scale.

Two branches handle the full uint256 domain. For x ≤ type(uint128).max, the input is pre-scaled by 1e36: cbrt(x · 1e36) = cbrt(v · 1e54) = cbrt(v) · 1e18 — Newton lands on the FP18 answer directly, bit-perfect. For x > type(uint128).max (where x · 1e36 would overflow), Newton runs on raw x and the result is post-scaled by 1e12.

The large-x branch trades a small amount of precision for domain coverage. Near the branch boundary, integer cbrt has ~13 significant digits, so the post-scale gives ~10⁻¹³ relative error — sub-FP18 but well below any DeFi-relevant tolerance. Precision improves quickly as x grows and integer cbrt gains significant digits; by x ≈ 10⁵⁴ the result is again bit-perfect.

The whole hot path stays in unchecked Yul assembly: ~340 gas, ~37% cheaper than Solady's cbrtWad at matching precision, with a strictly wider input domain (Solady reverts on large inputs).

Errors

ErrorTrigger
NoneNever reverts. Accepts any uint256 input. x == 0 returns 0; large x takes the post-scale branch with precision degrading to ~1e-13 near the branch boundary and tightening back to bit-perfect as x grows past 1e54.

Example

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

uint256 x = 8e18;             // x = 8.0
uint256 y = Math.cbrt(x); // y = 2e18