Math.cbrt()

ES6+

Returns the cube root of a number, correctly handling negatives: Math.cbrt(-8) is -2, because every real number has exactly one real cube root. Added in ES2015, it fills the gap left by Math.pow(x, 1/3), which returns NaN for negative bases under IEEE 754 rules.

Syntax

Math.cbrt(x)

Parameters

x number

A number

Return Value

number

The cube root of the given number

Examples

JavaScript
console.log(Math.cbrt(8));
console.log(Math.cbrt(27));
console.log(Math.cbrt(-8));
Output:
// 2 3 -2

📌 When to Use

Use Math.cbrt() whenever a cubic relationship must be inverted: recovering a side length from a volume, scaling 3D objects so volume changes linearly with a slider (side = cbrt(volume) keeps perceived size changes even), converting cubic units, physics formulas where quantities grow with the cube of size (mass versus length of similar bodies, Kepler-style period-radius relations), and data transformations that compress dynamic range while preserving sign. That last property is its quiet superpower: unlike sqrt, cbrt is defined for negatives, so it can normalize signed data, audio samples, error residuals, chart values spanning positive and negative, into a perceptually flatter scale without splitting on sign. Prefer it over the fractional-power form even for positive inputs: Math.pow(x, 1/3) is subtly wrong twice, it NaNs on negatives, and 1/3 itself is not exactly representable in binary, so the result can be one ulp off where cbrt is specified to be correctly rounded to the true cube root. Reserve the generic pow form for arbitrary exponents where no dedicated function exists, and pair cbrt with domain validation only for NaN and Infinity, since negatives, uniquely among the root functions, are perfectly legal input here.

⚠️ Common Mistakes

Using Math.pow(x, 1/3) for cube roots: it returns NaN for any negative x, because IEEE 754 defines negative-base with non-integer exponent as NaN, and the exponent 1/3 is stored as 0.333... (not exactly a third), so even positive results can differ in the last bit from the true root. Math.cbrt exists precisely to fix both problems.

Round-trip expectations: Math.cbrt(x) ** 3 does not always return exactly x (Math.cbrt(2) cubed is 2.0000000000000004), because each operation rounds independently. Comparisons after inversion need a tolerance, the standard Math.abs(a - b) < eps pattern, not strict equality.

Testing perfect cubes with Number.isInteger(Math.cbrt(n)): correct rounding makes this dependable for cubes within the safe-integer range, but beyond 2^53 the integer input itself is unrepresentable and the test breaks down; large-number cube checks need BigInt arithmetic.

Confusing cube root with dividing by 3 or with sqrt: scaling a volume slider by sqrt gives sides that grow too fast, and by /3 gives linear nonsense; the errors look plausible in UI testing because everything still moves monotonically. The relationship must match the geometry.

Assuming availability everywhere: Math.cbrt arrived with ES2015; long-obsolete ES5 targets need the sign-splitting polyfill Math.sign(x) * Math.pow(Math.abs(x), 1/3). Modern toolchains handle this, but copy-pasted legacy snippets sometimes reintroduce the pow form and its NaN bug.

✅ Best Practices

Reach for the dedicated root functions, Math.sqrt, Math.cbrt, before generic exponentiation: they document intent, define negative-input behavior sensibly, and are specified as correctly rounded where pow is not.

When inverting formulas, invert symbolically first: from V = s³ write s = Math.cbrt(V) directly rather than numerically solving; keep the pair of functions (volumeFromSide, sideFromVolume) adjacent and unit-tested against each other with tolerance-based assertions.

Use cbrt for sign-preserving compression of signed data before visualization: cbrtScaled = data.map(Math.cbrt) tames outliers in diverging datasets where a log scale would fail on zeros and negatives.

Validate the interesting inputs, NaN and ±Infinity flow through (Math.cbrt(Infinity) is Infinity), so boundary checks should use Number.isFinite; do not add a negative guard out of sqrt habit, negatives are valid here.

For other odd roots of negative numbers (fifth roots and so on), generalize the cbrt idea explicitly: Math.sign(x) * Math.abs(x) ** (1/5); only odd roots admit this treatment, even roots of negatives are genuinely undefined in the reals.

⚡ Performance Notes

Math.cbrt() is implemented natively (typically via optimized library routines rather than a single instruction), landing between sqrt and the transcendentals in cost: slower than Math.sqrt's hardware instruction, faster than or comparable to Math.pow with a fractional exponent, and easily fast enough for per-frame UI math, chart transforms over thousands of points, and physics steps. It allocates nothing and JITs cleanly. If a profiler ever does show cube roots dominating, a genuinely rare situation, the realistic remedies are algorithmic: hoist repeated roots of the same value, transform once into cbrt-space and work there, or move bulk array math into typed arrays where memory bandwidth, not the root, sets the ceiling. Do not attempt Newton-iteration replacements in JavaScript; the native implementation is already better than what user code can achieve.

🌍 Real World Example

Cube Side Length from Volume

Going from volume back to dimension is a routine engineering conversion: given a 3D print, a shipping container allocation, or a tank capacity, what side length or characteristic size does it imply? This example inverts V = s³ with Math.cbrt to recover the side, then derives dependent quantities like surface area, demonstrating the tolerance-based round-trip check that inverse-formula code should ship with. The same inversion sizes dice and packaging from target volumes, converts engine displacement to cylinder dimensions, and calibrates voxel sizes in scientific visualization.

function calculateCubeDimensions(volume) {
  const sideLength = Math.cbrt(volume);

  return {
    volume,
    sideLength: sideLength.toFixed(3),
    surfaceArea: (6 * sideLength * sideLength).toFixed(3),
    diagonal: (sideLength * Math.sqrt(3)).toFixed(3)
  };
}

console.log(calculateCubeDimensions(27));
// { volume: 27, sideLength: '3.000', surfaceArea: '54.000', diagonal: '5.196' }

console.log(calculateCubeDimensions(1000));
// { volume: 1000, sideLength: '10.000', surfaceArea: '600.000', diagonal: '17.321' }

Related Methods