Math.clz32()
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
概述
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.
示例
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 的个数。
先看以下代码:
const a = 32776; // 00000000000000001000000000001000(16 个前导 0)
Math.clz32(a); // 16
const b = ~32776; // 11111111111111110111111111110111(对 32776 取反,0 个前导 0)
Math.clz32(b); // 0(这与 a 中有多少个前导 0 等价)
通过以上方法,clon
函数可以定义如下:
const clz = Math.clz32;
function clon(integer) {
return clz(~integer);
}
现在,我们可以进一步实现计算“尾随 0”和“尾随 1”的个数了。下面的 ctrz
函数将第一个 1 之后的高数位全部置为 1 然后取反,再用 Math.clz32
求得尾随 0 的个数。
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 就是用来干这个的。
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