jsguides

Math.clz32()

Math.clz32(x)

The Math.clz32() function returns the number of leading zero bits in the 32-bit binary representation of a number. The name “clz32” stands for “count leading zeros 32”. This function is particularly useful in low-level programming, graphics, and performance-critical code where bit manipulation matters.

Syntax

Math.clz32(x)

Parameters

  • x — Any number. Non-numeric values are coerced to numbers.

Return Value

A number between 0 and 32 representing the count of leading zero bits in the 32-bit binary representation of the argument. A return of 32 means the value is 0 (all bits are zero).

Examples

Basic usage

console.log(Math.clz32(1));
// 31

console.log(Math.clz32(0));
// 32

console.log(Math.clz32(-1));
// 0

The three results above — 31, 32, and 0 — only make sense when you picture the 32-bit binary layout. Each call reads the binary form and counts zero bits from the left. The next block walks through several more values with their bit patterns annotated to make the counting visible.

Understanding the output

// 1 in 32-bit binary: 00000000000000000000000000000001
// 31 leading zeros
console.log(Math.clz32(1));
// 31

// 2 in 32-bit binary: 00000000000000000000000000000010
// 30 leading zeros
console.log(Math.clz32(2));
// 30

// 256 in 32-bit binary: 00000000000000000000000100000000
// 23 leading zeros
console.log(Math.clz32(256));
// 23

// 0b10000000000000000000000000000000 (highest bit set)
// 0 leading zeros
console.log(Math.clz32(2147483648));
// 0

Each call reads the 32-bit binary form and counts zeros from the left. But Math.clz32() does not assume you hand it a clean integer — it first coerces the input through the ToUint32 abstract operation. Fractional parts are discarded, and negative values wrap around into the unsigned 32-bit range.

Integer conversion

// Non-integers are converted to 32-bit integers first
console.log(Math.clz32(3.7));
// 30 (3 becomes 0b00000000000000000000000000000011)

// Negative numbers are treated as unsigned 32-bit integers
console.log(Math.clz32(-1));
// 0 (all bits are 1s in two's complement)

Common Patterns

Once you understand how clz32 interprets numbers, you can build useful utilities on top of it. The leading-zero count is the inverse of the highest-set-bit position — a simple subtraction from 31 gives you the index of the most significant 1-bit. This relationship powers several common low-level patterns.

Finding the bit position of the highest set bit

function highestBitPosition(n) {
  if (n === 0) return 0;
  return 31 - Math.clz32(n);
}

console.log(highestBitPosition(256));
// 8

console.log(highestBitPosition(1024));
// 10

console.log(highestBitPosition(1));
// 0

Knowing the highest bit position lets you reason about a number’s magnitude in powers of two. For power-of-two tests, clz32 provides an alternative to the classic bitwise trick n & (n - 1) === 0, though the classic approach is usually simpler and more readable.

Checking if a number is a power of two

function isPowerOfTwo(n) {
  return n > 0 && (n & (n - 1)) === 0;
}

function clz32IsPowerOfTwo(n) {
  return n > 0 && Math.clz32(n) + Math.clz32(n - 1) === 31;
}

console.log(isPowerOfTwo(256));
// true

console.log(clz32IsPowerOfTwo(256));
// true

console.log(isPowerOfTwo(100));
// false

console.log(clz32IsPowerOfTwo(100));
// false

The relationship between clz32 and bit position also enables division by powers of two through right-shifts. By computing how many bit positions to shift from the divisor’s leading zero count, you can replace a division with a faster bitwise operation — just be aware this only works for divisors that are exact powers of two.

Fast integer division by powers of two

function divideByPowerOfTwo(n, divisor) {
  // Works only for positive divisors that are powers of 2
  const shift = Math.clz32(divisor) - 31;
  return n >> shift;
}

console.log(divideByPowerOfTwo(1024, 4));
// 256

console.log(divideByPowerOfTwo(100, 2));
// 50

How Math.clz32() works

Math.clz32(x) converts x to a 32-bit unsigned integer (via the ToUint32 abstract operation), then counts the number of consecutive zero bits starting from the most significant bit (bit 31). For example, the value 1 has the binary representation 00000000000000000000000000000001 — 31 leading zeros. The value 0 has 32 leading zeros (all bits are zero). Negative numbers in 32-bit representation have bit 31 set, so Math.clz32(-1) returns 0.

Why 32-bit?

clz32 operates on 32-bit integers because JavaScript’s bitwise operators all work with 32-bit signed integers. Any floating-point number passed to clz32 is first converted to an integer by truncating the fractional part and taking the low 32 bits (via the ToInt32 abstract operation). Values outside the 32-bit signed range wrap around.

Performance characteristics

Math.clz32() maps directly to a CPU instruction (BSR/LZCNT on x86, CLZ on ARM) in optimised JIT code. This makes it very fast for bit manipulation tasks in tight loops — faster than a manual loop counting leading zeros. It is particularly useful in WebAssembly interop and performance-sensitive graphics code.

Practical use: floor(log2(n))

One common use of clz32 is computing the floor of log base 2 of a positive integer — the position of the highest set bit:

function log2floor(n) {
  return 31 - Math.clz32(n);
}

log2floor(1);    // 0
log2floor(2);    // 1
log2floor(8);    // 3
log2floor(1000); // 9

This is equivalent to Math.floor(Math.log2(n)) but avoids floating-point arithmetic and is faster.

See Also