cbrt
MathComputes 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
function cbrt(uint256 x) internal pure returns (uint256 y)Parameters
| Name | Type | Description |
|---|---|---|
| x | uint256 | Input in 18-decimal fixed-point format (1e18 = 1.0). Any value in [0, uint256.max] accepted. |
Returns
| Name | Type | Description |
|---|---|---|
| y | uint256 | Cube root ∛x in 18-decimal fixed-point format. |
Bounds
| Bound | Value |
|---|---|
| Input domain | Full 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
0whenx == 0— handled by the algorithm's natural underflow via EVM'sdiv(0, 0) = 0semantic, no explicit guard. - Never reverts. Handles the full
[0, uint256.max]range via a two-branch split attype(uint128).max. - Uses the
CLZopcode (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
| Error | Trigger |
|---|---|
| None | Never 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
import "defimath-lib/contracts/math/Math.sol";
uint256 x = 8e18; // x = 8.0
uint256 y = Math.cbrt(x); // y = 2e18