幂次方计算_六 | x的n次方

点击上方蓝字关注我们

小葱今天想开个方

却惨遭"滑铁卢"

cf7fb78f20de3d65db8c0dc8fac482c2.png

生气

所以本葱立马照模照样搞了一个

18207e4a3511dd61b7a06e10d2c8509d.png

快速调用Math.pow()的方法

function mypow(x, n) {  return Math.pow(x, n)}

90aac344d590d9b353c3903f47195722.png

5b4531a2e2fe7e9179dc4f693671d590.png

噢哟

原来也没办法显示

让我们看看

什么是

Infinity

b3410361479e919f961173ed095fc022.png

也就是说数字太大了

显示不了

那它也许只是显示问题

想算还是可以的

那似乎需要改造一下

ec36b5b30e0d9363eccb0a3769031d26.png

首先

得把开方功能安排一下

求xⁿ

其实就是通过循环

将n个x乘起来

那自然n等于多少就得循环多少遍

function foreach(x, n) {  let res = 1  for (let i = 0; i < n; i++) {    res *= x  }  return res}

7c22fdc124a87b2405953e55752cd865.png

该出现的问题还是出现了

371bae6417fa7167471d225dff78d443.gif371bae6417fa7167471d225dff78d443.gif8bf9628b416572892b0e9925b5d97715.gif

数字显示不了

那我们应该考虑的是字符串

将乘法改为字符串相乘

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},

噔噔蹬蹬

fc94fd2bfed48352853c350bad8b7ae7.png

这个数字通过验证

确实是对的

循环1024次只用了16毫秒

还阔以拉

加两个0试试

aaf488fe9ea7b345edc5e55496ab1673.png

72796 ms -> 1分12秒算完

问题不大

问题不大??

39dedb74bd478b9e099fd4f8862835cc.png

改改改

不知道施主有没有听说过

快速幂

快速幂呀

它的本质其实是分治算法

举个栗子

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次

这个方式也就是

指数乘除法定理

底数不变指数相加减

1e7753933050b6b69c739031ae6f8067.png

那有人就问了

谁每次开方刚好64的

我要是65呢

7cc00b01624131543ff8d099f26b826f.png

你要是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

总结一下

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 + '')}

3b0e589e926283c305f25b2507b7e8a6.png

这一代小葱计算

比上一代快了10

当然如果你不在乎内存

这样就够了

371bae6417fa7167471d225dff78d443.gif371bae6417fa7167471d225dff78d443.gif8bf9628b416572892b0e9925b5d97715.gif

递归自然是通过额外的栈空间

能循环就不递归

不是没有道理的

回想一下

为什么我们会使用递归

因为我们不知道

什么时候要多乘以一个x

有请下一个方法

这里不得不说一下二进制

还是举例

277

02774f2db8d69b481fd1142aeee309ad.png

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}

918191644f353bf8f1b2d81ef90c9a2c.png

至此

所有方法都介绍完了

自行测试

哈哈哈

65de3f57841b00949c2cc271367cead8.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值