点击上方蓝字关注我们
小葱今天想开个方
却惨遭"滑铁卢"
生气
所以本葱立马照模照样搞了一个
快速调用Math.pow()的方法
function mypow(x, n) { return Math.pow(x, n)}
噢哟
原来也没办法显示
让我们看看
什么是
Infinity
也就是说数字太大了
显示不了
那它也许只是显示问题
想算还是可以的
那似乎需要改造一下
首先
得把开方功能安排一下
求xⁿ
其实就是通过循环
将n个x乘起来
那自然n等于多少就得循环多少遍
function foreach(x, n) { let res = 1 for (let i = 0; i < n; i++) { res *= x } return res}
该出现的问题还是出现了
数字显示不了
那我们应该考虑的是字符串
将乘法改为字符串相乘
mulStr(a, b) { // 先定义一个结果集 let r = new Array(a.length + b.length).fill(0) // 从个位数往十位百位千位...算 for (let i = a.length - 1; i >= 0; i --) { for (let j = b.length - 1; j >= 0; j --) { let k = i + j + 1 let t = r[k] + a.charAt(i) * b.charAt(j) r[k] = t % 10 r[k - 1] += Math.floor(t / 10) } } // 去掉多余的0 let k = 0 while (r[k] === 0 && k <= r.length - 2) { k++ } return r.join('').slice(k)}
将数字相乘改为字符串相乘
就不会有显示不出来的问题
但这个方法对负数和小数点
好像不怎么友好
毕竟是百度扒别人的
就没那么多要求了
将刚刚的方法改造一下
foreach(x, n) { let res = '1' for (let i = 0; i < n; i++) { res = this.mulStr(res, x + '') // 字符串相乘 } return res},
噔噔蹬蹬
这个数字通过验证
确实是对的
循环1024次只用了16毫秒
还阔以拉
加两个0试试
72796 ms -> 1分12秒算完
问题不大
问题不大??
改改改
不知道施主有没有听说过
快速幂
快速幂呀
它的本质其实是分治算法
举个栗子
264
(底数为2 指数为64)
2 x 2 = 4 => 2²
2 x 2 x 2 x 2 = 16 => 24
相当于就是4 x 4 = 16
以此类推
2 → 22 → 24 → 28 → 216 → 232 → 264
原本需要算64次的现在只需要算7次
这个方式也就是
指数乘除法定理
底数不变指数相加减
那有人就问了
谁每次开方刚好64的
我要是65呢
哎
你要是65次方
是不是就是算64次方再乘一个2
再举个例子
277
2 → 22 → 24 → 29 → 219 → 238 → 277
如果你从左往右看
你会想
为什么4之后就是9
9之后是19
38之后是77
(以上说的是指数)
但是如果你从右往左看
77 % 2 != 0
所以要多乘一次
就是 38 + 38 + 1 = 77
(以上说的是指数)
那带上底数
就是
238 x 238 x 2 = 277
(底数不变,指数相加减)
从后往前算
那想想是不是用递归呀
递归的优势就来了
![90fc97a190367d90ff05d2e3e95a9ffc.png](https://i-blog.csdnimg.cn/blog_migrate/26fdf912cb0b21c9b406c66fc0879ee2.png)
总结一下
1、当我们要计算 xⁿ 我们可以递归计算出y = xn/2
2、根据递归计算,n如果是偶数,那 xⁿ = y²,如果为奇数,那xⁿ = y² * x
3、递归的边界为 n = 0,任意数的 0 次方均为 1
function quickMul(x, n) { if (n == 0) { return '1'; } let y = this.quickMul(x, parseInt(n / 2)) return n % 2 == 0 ? this.mulStr(y, y) : this.mulStr(this.mulStr(y, y), x + '')}
这一代小葱计算
比上一代快了10倍
当然如果你不在乎内存
这样就够了
递归自然是通过额外的栈空间
能循环就不递归
不是没有道理的
回想一下
为什么我们会使用递归
因为我们不知道
什么时候要多乘以一个x
有请下一个方法
这里不得不说一下二进制
还是举例
277
77 -> 1001101
从右往左读
则 1x1+0x2+1x4+1x8+0x16+0x32+1x64
因为77是次方
所以转换为二进制也是次方
再运用
指数乘除法定理
底数不变指数相加减
就是所有加号都转为同底相乘
21x1x20x2x21x4 x21x8 x20x16 x20x32 x21x64
合计一下
因为任何非零数的零次幂为1
所以得出
2x24x28 x264
这样是不是就全部都和刚开始说的那样
既然逻辑理清楚了
上代码
function binaryPow(x, n) { if (x == 0) return 0 let res = '1' x += '' while(n > 0) { if((n & 1) == 1) res = this.mulStr(res, x) if ((n >>= 1) > 0) { x = this.mulStr(x, x) } } return res}
至此
所有方法都介绍完了
自行测试
哈哈哈