#70 Math.clz32 的 Polyfill


  • 0
    administrators

    ES6 新增了 Math.clz32 方法,可以让我们获取到一个整数的无符号 32 位的二进制形式有多少位前置的 0。例如:

    // 1 的 32 位二进制表示:0b00000000000000000000000000000001
    // 有 31 位前置的 0
    Math.clz32(1) // => 31
    

    请你完成 clz32 来达到和 Math.clz32 的同样的功能。如果输入的是能够转换成数字的,先转换成数字再进行计算:

    Math.clz32('2') // => 30
    

    如果不能转换成数字的,返回 32

    Math.clz32('good') // => 32
    

    总而言之,你的函数的返回结果要和 Math.clz32 保持一致。


  • 0

    暴力解法

    const clz32 = (num) =>
      isNaN(num) ||
      null == num ||
      !Number.isFinite(Number(num)) ||
      Math.floor(num % 0xffffffff) == 0 ||
      num >= 1.5430679999992199242579968e+25 ||
      num <= -1.5430679999992199242579968e+25 ?
      32 :
      32 - Math.floor(num < 0 ? 0xffffffff + (num % 0xffffffff) : num % 0xffffffff).toString(2).length
    

  • 0
    administrators

    @CodeHz 有点暴力,有很简短的解法。


  • 0

    @胡子大哈 主要是边界条件太多。。否则可以直接用Float64Array解决的(通过浮点数内存布局)
    上面那个代码有问题,,,魔法数字并不是正确的

    const clz32 = (num) => {
      let tnum = Math.floor(num)
      if (isNaN(num) || null == num || !Number.isFinite(tnum))
        return 32
      if (tnum < 0)
        tnum = Number.MAX_SAFE_INTEGER + tnum
      const m = tnum.toString(2).match(/1.{0,31}?$/g)
      return m == null ? 32 : 32 - m[0].length
    }
    

  • 0

    @胡子大哈 你说的简短的解法是不是指这种

    const clz32 = (num) => {
      for (let pc = 1 << 31, i = 0; i < 32; [i, pc] = [i + 1, pc >>> 1])
        if ((pc & num) !== 0) return i;
      return 32
    }
    

  • 0
    administrators

    @CodeHz 不用循环也可以


  • 0

    @胡子大哈 那大概就是MDN上的那个polyfill了。。然后github上有修改版

    'use strict';
    module.exports = Math.clz32 || function (x) {
    	return (x >>>= 0) ? 31 - Math.floor(Math.log(x + 0.5) * Math.LOG2E) : 32;
    };
    

    不过这个性能比不上循环的(很显然用字符串的是最慢的,log其次,再是循环的)。。当然最快的方法是下面这种(来自 https://jsperf.com/read-leading-zeros/25)

    function clz32(x) {
      x = x | 0;
      // http://en.wikipedia.org/wiki/Find_first_set
      // + trying to avoid uint32 to int32 conversions
      if (x === 0) {
        return 32;
      }
      var n = 0;
      if ((x & -65536)      === 0) { n = n | 16; x = x << 16; }
      if ((x & -16777216)   === 0) { n = n | 8; x = x << 8; }
      if ((x & -268435456)  === 0) { n = n | 4; x = x << 4; }
      if ((x & -1073741824) === 0) { n = n | 2; x = x << 2; }
      if ((x & -2147483648) === 0) { n = n | 1; }
      return n;
    }
    

  • 0

    const clz32 = (num) => {
      let v = num >>> 0
      return v ? 32 - v.toString(2).length : 32
    }
    

    前端表单验证工具 https://github.com/WLDragon/SMValidator


登录后回复
 

与 ScriptOJ 的连接断开,我们正在尝试重连,请耐心等待