Learn JavaScript

Math.clz32() - метод для подсчёта ведущих нулей в 32-битном числе в JavaScript

Math.clz32() считает количество ведущих нулей в 32-битном двоичном представлении числа.

Название можно запомнить так:

  • clz = count leading zeroes
  • 32 = работа идёт с 32-битным числом

Это уже не про обычную математику, а про биты и двоичное представление.

Синтаксис

Math.clz32(x)

x - значение, которое будет приведено к беззнаковому 32-битному целому числу.

Что делает Math.clz32()

Метод возвращает, сколько нулей стоит слева в 32-битной двоичной записи числа.

console.log(Math.clz32(1));    // 31
console.log(Math.clz32(2));    // 30
console.log(Math.clz32(1000)); // 22

Это значит:

  • у 1 только последний бит равен 1, поэтому слева 31 ноль
  • у 2 двоичная запись чуть длиннее, поэтому ведущих нулей уже 30
  • у 1000 ведущих нулей 22

Что возвращает Math.clz32()

Math.clz32() возвращает число типа number.

const result = Math.clz32(8);

console.log(result);        // 28
console.log(typeof result); // "number"

Результат всегда находится в диапазоне от 0 до 32.

Как это выглядит в двоичной записи

На примере 1 это проще всего увидеть.

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

Слева действительно 31 ноль.

Ещё пример:

// 00000000000000000000001111101000
console.log(Math.clz32(1000)); // 22

У числа 1000 двоичная часть начинается не сразу, поэтому слева остаётся 22 нуля.

Почему Math.clz32(0) равно 32

Это один из самых важных случаев.

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

У нуля 32-битная двоичная запись выглядит так:

00000000000000000000000000000000

То есть все 32 бита равны нулю.

Результат всегда от 0 до 32

У метода не бывает значений меньше 0 или больше 32.

console.log(Math.clz32(0));          // 32
console.log(Math.clz32(1));          // 31
console.log(Math.clz32(4294967295)); // 0

Полезно помнить:

  • 32 означает, что число после преобразования стало 0
  • 0 означает, что самый левый бит уже равен 1

Значение сначала приводится к 32-битному числу

Это самый важный нюанс при работе с Math.clz32().

Метод не смотрит на исходное число как есть. Сначала он превращает его в беззнаковое 32-битное целое.

Из-за этого некоторые результаты могут удивлять.

Отрицательные числа

Отрицательные значения тоже приводятся к беззнаковому 32-битному формату.

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

Например, -1 после такого преобразования выглядит как число, у которого все 32 бита равны 1.

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

Поэтому ведущих нулей здесь нет вообще.

Дробные числа

Дробные значения сначала приводятся к 32-битному целому числу.

console.log(Math.clz32(1.9)); // 31
console.log(Math.clz32(0.5)); // 32

Здесь важно понимать:

  • 1.9 после преобразования становится 1
  • 0.5 после преобразования становится 0

Поэтому и результат получается таким.

Большие числа

Очень большие значения тоже могут вести себя неожиданно, потому что метод работает только с 32 битами.

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

Во втором случае значение выходит за пределы 32 бит и после преобразования становится 0.

Поэтому результатом будет 32.

Math.clz32() и двоичная длина числа

Math.clz32() удобно использовать, если нужно понять, сколько бит реально занимает число.

Например:

const value = 1000;
const bits = 32 - Math.clz32(value);

console.log(bits); // 10

То есть у числа 1000 значимая двоичная длина равна 10.

Это соответствует и обычной записи:

console.log((1000 >>> 0).toString(2)); // "1111101000"

Math.clz32() и toString(2)

Эти подходы могут использоваться рядом, но делают немного разное.

console.log(Math.clz32(1000));          // 22
console.log((1000 >>> 0).toString(2));  // "1111101000"
  • Math.clz32() считает нули слева в 32-битной записи
  • toString(2) показывает само двоичное число без полного 32-битного дополнения

Если вам нужен именно подсчёт ведущих нулей, Math.clz32() удобнее и нагляднее.

Без аргумента

Если вызвать Math.clz32() без аргумента, результатом будет 32.

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

Это может показаться неожиданным, но метод попытается обработать undefined, приведёт его к 0 в 32-битном формате и посчитает ведущие нули у нуля.

Неявное приведение типов

Math.clz32() сначала пытается привести аргумент к числу, а потом к 32-битному беззнаковому целому.

console.log(Math.clz32("1"));    // 31
console.log(Math.clz32(null));   // 32
console.log(Math.clz32(true));   // 31
console.log(Math.clz32(false));  // 32

На практике лучше передавать в метод уже готовое число.

Массивы и странные значения

Из-за приведения типов некоторые значения могут вести себя неочевидно.

console.log(Math.clz32([]));     // 32
console.log(Math.clz32([5]));    // 29
console.log(Math.clz32([1, 2])); // 32

Это ещё одна причина, почему лучше не полагаться на неявное преобразование.

NaN и Infinity

Для специальных значений результат будет таким:

console.log(Math.clz32(NaN));       // 32
console.log(Math.clz32(Infinity));  // 32
console.log(Math.clz32(-Infinity)); // 32

Это полезно помнить:

  • NaN даёт 32
  • Infinity даёт 32
  • -Infinity даёт 32

Причина в том, что после преобразования все эти значения становятся 0 в 32-битном формате.

Число не меняется

Math.clz32() не изменяет исходное значение. Он только возвращает новый результат.

const value = 1000;
const result = Math.clz32(value);

console.log(value);  // 1000
console.log(result); // 22

Когда это полезно

Math.clz32() удобно использовать, когда:

  • вы работаете с битовыми операциями
  • нужно узнать двоичную длину числа
  • вы пишете низкоуровневую логику
  • нужно быстро анализировать 32-битное представление значения

Пример:

const value = 16;
const leadingZeros = Math.clz32(value);

console.log(leadingZeros); // 27

Частые ошибки

Думать, что метод считает все нули в числе

console.log(Math.clz32(8)); // 28

Метод считает не все нули, а только ведущие нули слева в 32-битной двоичной записи.

Ожидать NaN без аргумента

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

Здесь будет не NaN, а 32.

Забывать про преобразование к 32-битному числу

console.log(Math.clz32(1.9));        // 31
console.log(Math.clz32(4294967296)); // 32

Метод работает не с исходным значением как есть, а с его 32-битной версией.

Быстрая памятка

  • Math.clz32(x) считает ведущие нули в 32-битной двоичной записи
  • clz означает count leading zeroes
  • метод возвращает number
  • результат всегда находится в диапазоне от 0 до 32
  • Math.clz32(0) возвращает 32
  • Math.clz32(1) возвращает 31
  • перед вычислением значение приводится к беззнаковому 32-битному числу
  • отрицательные, дробные и очень большие числа могут давать неожиданный результат

Коротко

Math.clz32() - это стандартный способ посчитать количество ведущих нулей в 32-битном двоичном представлении числа в JavaScript. Главное, что нужно запомнить: метод всегда работает именно с беззнаковым 32-битным значением, поэтому 0 даёт 32, а дробные, отрицательные и слишком большие числа сначала преобразуются перед вычислением.