Math.clz32()
============

概述
--

**`Math.clz32()`** 函数返回一个数字在转换成 32 无符号整形数字的二进制形式后，开头的 0 的个数，比如 `1000000` 转换成 32 位无符号整形数字的二进制形式后是 `00000000000011110100001001000000`, 开头的 0 的个数是 12 个，则 `Math.clz32(1000000)` 返回 `12`.

语法
--
```

Math.clz32 (x)
```

### 参数

x

一个数字。

描述
--

"clz32" 是 CountLeadingZeroes32 的缩写。

如果 `x` 不是数字类型，则它首先会被转换成数字类型，然后再转成 32 位无符号整形数字。

如果转换后的 32 位无符号整形数字是 `0`, 则返回 `32`, 因为此时所有位上都是 `0`.

`NaN`, `Infinity`, `-Infinity` 这三个数字转成 32 位无符号整形数字后都是 `0`.

这个函数主要用于那些编译目标为 JS 语言的系统中，比如 Emscripten.

示例
--


```js
Math.clz32(1); // 31
Math.clz32(1000); // 22
Math.clz32(); // 32

const stuff = [
  NaN,
  Infinity,
  -Infinity,
  0,
  -0,
  false,
  null,
  undefined,
  "foo",
  {},
  [],
];
stuff.every((n) => Math.clz32(n) === 32); // true

Math.clz32(true); // 31
Math.clz32(3.5); // 30
```

计算前导 1 的个数
----------

目前 javascript 尚未提供 `Math.clon` 函数来计算前导 1 的个数（之所以叫“clon”而非“clo”，是因为“clo”与“clz”太过相似，特别对那些母语不是英语的人来说），但是你可以通过将一个数取反并将其作为 `Math.clz32` 的参数来实现 clon 函数。其中的原理非常简单，因为对 1 取反是 0，反之亦然，所以用 `Math.clz32` 计算前导 0 的个数就变成计算前导 1 的个数。

先看以下代码：


```js
const a = 32776; // 00000000000000001000000000001000（16 个前导 0）
Math.clz32(a); // 16

const b = ~32776; // 11111111111111110111111111110111（对 32776 取反，0 个前导 0）
Math.clz32(b); // 0（这与 a 中有多少个前导 0 等价）
```


通过以上方法，`clon` 函数可以定义如下：


```js
const clz = Math.clz32;

function clon(integer) {
  return clz(~integer);
}
```


现在，我们可以进一步实现计算“尾随 0”和“尾随 1”的个数了。下面的 `ctrz` 函数将第一个 1 之后的高数位全部置为 1 然后取反，再用 `Math.clz32` 求得尾随 0 的个数。


```js
var clz = Math.clz32;
function ctrz(integer) {
  // 计算尾随 0 个数
  // 1. 将第一个 1 之后的高数位全部置为 1
  // 00000000000000001000000000001000 => 11111111111111111111111111111000
  integer |= integer << 16;
  integer |= integer << 8;
  integer |= integer << 4;
  integer |= integer << 2;
  integer |= integer << 1;
  // 2. 然后，对该数取反，此时低位的 1 的个数即为所求
  return (32 - clz(~integer)) | 0; // `| 0` 用于保证结果为整数
}
function ctron(integer) {
  // 计算尾随 1 个数
  // JavaScript 中没有移位补 1 的运算符
  // 所以下面的代码是最快的
  return ctrz(~integer);
  /\* 为了看起来比较对称，你也可以使用以下代码：
 // 1. 将第一个 0 之后的高数位全部置为 0
 integer &= (integer << 16) | 0xffff;
 integer &= (integer << 8 ) | 0x00ff;
 integer &= (integer << 4 ) | 0x000f;
 integer &= (integer << 2 ) | 0x0003;
 integer &= (integer << 1 ) | 0x0001;
 // 2. 然后，对该数取反，此时低位的 0 的个数即为所求
 return 32 - clon(~integer) |0;
 \*/
}
```


将以上函数改写成 ASM.JS 模块——然后，你就可以去跟别人炫耀了！ASM.JS 就是用来干这个的。


```js
var countTrailsMethods = (function (stdlib, foreign, heap) {
  "use asm";
  var clz = stdlib.Math.clz32;
  function ctrz(integer) {
    // 计算尾随 0 个数
    integer = integer | 0; // 确保是整数
    // 1. 将第一个 1 之后的高数位全部置为 1
    // ASMjs 中不允许^=、&=、和 |=
    integer = integer | (integer << 16);
    integer = integer | (integer << 8);
    integer = integer | (integer << 4);
    integer = integer | (integer << 2);
    integer = integer | (integer << 1);
    // 2. 然后，对该数取反，此时低位的 1 的个数即为所求
    return (32 - clz(~integer)) | 0;
  }
  function ctron(integer) {
    // 计算尾随 1 个数
    integer = integer | 0; // 确保是整数
    return ctrz(~integer) | 0;
  }
  // 蛋疼的是，ASM.JS 必须使用糟糕的 object 类型：
  // unfourtunately, ASM.JS demands slow crummy objects:
  return { a: ctrz, b: ctron };
})(window, null, null);
var ctrz = countTrailsMethods.a;
var ctron = countTrailsMethods.b;
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-math.clz32 |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `Math`
* `Math.imul`