和v8干架之pow函数再实现

来源:互联网 发布:Mysql解除外键约束 编辑:程序博客网 时间:2024/05/16 06:48

首先,吹逼可以不用打草稿,能干过v8我还在这个时候写代码?

正题

说明

环境是node,别的系统配置没意义 ,相对比对,实现一个pow函数,然后和v8的比下,顺带试试各种优化性能的江湖传说

第一个实现

function pow(x,e){    if(e==0)return 1;    else if(e==1)return x;    else if(e%2)return pow(x*x,(e-1)/2)*x;    else  return pow(x*x,e/2); };

很眼熟,基本和c里面差不多
然后本着递归不靠谱,先实现一个用栈模拟递归的数组实现

第二个实现

function pow(x,e){    var i = e;    var m=[];    var index =0 ;    if(e==0)return 1;    if(e==1)return x;    while(1){        //console.log(i);        if(i==1){            m.push(x);            break ;        }        else if(i==2){            m.push(x*x);            break;        }        else{            if(i%2){                m.push(x);                i=(i-1)/2 ;            }            else {                m.push(1);                i/=2;            }        }    };    for(i=(m.length-1);i>0;i--)    {        m[i-1]=m[i]*m[i]*m[i-1];    }    return m[0];};

代码量一下子上来,然后测试,大概就是给个时间间隔,中间跑很多次函数结果:
native:70,code1:11000;code2:13000
嗯,这是个假数组实现,还不如递归,可见一般情况下,递归还是不错的选择,但是,如果再想下,思考点什么邪术,就可以干一波大事了
首先考虑一下,pow的指数值其实是局限的,或者说大了也没啥卵用,然后呢,这种二分对干的情况,,不由得想起了二进制,的确可以,细节略过,反正就是对比一下数组模拟,来个二进制模拟,这里用了es6的位操作(c里面很常见的套路),然后用了系统计算函数(罪过罪过,说不定就是靠这个函数优化的性能),然后有了下面版本

第三个实现

function pow(x,e){    var res =x;    if(e==0)return 1;    if(e==1)return x;    if(x==1)return 1;    var k = 32-Math.clz32(e)-1;    //console.log('fd'+res);    for(var i =0 ; i<k;i++)    {        if(e&(1<<(k-i-1))){            res=(res*res*x) ;}        else {            res*=res;        }    }    return res ;};

效果是:native:90,code3:1000
真是飞跃。。。。
接着实验各种邪术江湖传闻,比较靠谱的是:
避免全局查找,将res等变量声明为全局,大概慢两倍或者更多
然后之前数组实现时,将push换为索引,没啥大的改变。
将内部var声明为let,大概也是慢两倍多,安全和效率会有冲突
而使用arguments来直接用实参比用形参访问慢(要计算)
然后有些不靠谱(可能我说的不对):
明确循环终止条件,while比for(;;)好什么的,,没啥用
异步,这个不考虑,没啥用
然后,发现了一个天大的秘密,用几个函数一层层套,居然执行更快了,,,,不过3层左右就可以了,套个9层还是会变慢
然后还有if..eles 比switch ..case好,可能IE会好,不过因此变成了个逼格不错的样子

第四个实现

function pow(x,e){    var res =x;    if(e===0)return 1;    if(e===1)return x;    if(x===1)return 1;    //获得e的二进制有效长    var k = 32-Math.clz32(e)-1;//-1为res有初始赋值    var i = 0 ;    for(var  i =0 ; i<k;i++)    {        res=e&(1<<(k-i-1))?(res*res*x):(res*res);    }    return res ;};

果然搞个这个条件选择就是感觉不一样了,但其实也没怎么快

原创粉丝点击