JavaScript大数相加相乘的实现方法实例


Posted in Javascript onOctober 18, 2020

前言

JavaScript 中的最大安全整数是 2 ^{53} ? 1 ,即 9007199254740991,当我们进行超出这个范围的数值计算的时候就无法得到精确的值,而是一个近似值,比如我们计算 9007199254740991 + 10 得到的结果是 9007199254741000。本文讲一下如何利用字符串在 JavaScript 中实现大数相加相乘。

相加

用字符串实现相加相乘基本思路就是按照我们在纸上进行竖式运算一样。对于加法,我们需要将两个数 num1 和 num2 上下对齐,然后从个位开始计算两个数对应位的和,循环到最高位,将每一次运算的结果保存到一个数组 result 中去,最终用 Array.prototype.join() 方法还原成一个数组。

这里为了保持循环的正常进行,我们需要保证两个字符串位数相等,所以我们要用 String.prototpye.padStart() 方法将位数比较小的那一个字符串的前面用 '0' 补齐。

按位相加有个问题就是进位如何保存,我的思路是这样的。当我们相加 num1[i] 和 num2[i] 的时候,得到的最多是一个两位数,它将影响 result 的两位,即当前的 result[0] 位置和即将 unshift 到 result 中的一位。当前的 result[0] 位置的数就是计算 [i -1] 是得到的数的高位(即进位),我们将我们计算的值加上进位,得到的数在分成两位分别放到 result 中。

所以总结一下就是我们计算 num1[i] + num2[i] 得到一个两位数,这个两位数要先和 num1[i-1] + num2[i-1] 的结果的进位(即 result[0] 相加,然后在分成 high 和 low 两位,将 result[0] 的值用 low 位替换,然后将 high 位 unshift 到 result 最前面。可以参考下图理解。

JavaScript大数相加相乘的实现方法实例

所以我们每次计算都是确定一位和下一位的进位。最后代码如下:

let add = function (num1, num2) {
 if (isNaN(num1) || isNaN(num2)) return '';
 if (num1 === '0' || num2 === '0') return (num1 === '0' ? num2 : num1);

 let len = Math.max(num1.length, num2.length);
 num1 = num1.padStart(len, '0');
 num2 = num2.padStart(len, '0');

 let result = [];

 for (let i = len - 1; i >= 0; i--) {
  let sum = Number(num1[i]) + Number(num2[i]) + (result[0] || 0);
  let low = sum % 10;
  let high = Math.floor(sum / 10);

  result[0] = low;
  result.unshift(high);
 }
 return result.join('');
}

console.log(add('10', '9007199254740991')) //09007199254741001

代码中我们加了两个判断,判断两个参数是否是合法数字格式,以及如果一个数是 '0' 则直接返回另一个数。

相乘

相乘的逻辑要比相加复杂一点,但是总体思路还是根据竖式来实现算法,我画了一张图,我们借助图来说明。

JavaScript大数相加相乘的实现方法实例

相乘是一个两层循环,我们要循环一个数的位,每一位再与另一个数循环的每一位相乘。我们每次相乘的结果最多是一个两位数。但是与相加不同的是,相加的 high 每次都是 unshift 进去即可,而相乘的高位也要与 result 的位进行运算。

我们来看一看相乘的规律,当我们用 num1[i] * num2[j] 的时候,可能得到两位数,也可能得到一位数,我们都统一算作两位数,高位没有的就用 0 补齐,那么最后我们得到的结果将是一个 i + j 位的数(开头可能存在补齐的 0)。而我们每次计算 num1[i] * num2[j] 的结果影响到的都是 result 中的 i + j 和 i + j + 1 位。

和加法中逻辑一样,我们将 num1[i] * num2[j] 的结果和 result[i + j + 1] 相加,得到的结果分为 low 和 high 分别存入 reslut 的 [i + j +1] 和 [i +j] 中。但是这里要注意,和加法不同,加法的高位直接存入就可以,我们这里的 high 对应的 result[i + j] 可能已经有值了,我们需要将已经存在的值加上。

high 和 result[i +j] 的相加可能存在进位怎么办呢,看上图中右边的当前 result 值中我们可以看到有些位存了不止一位数,我们将 high + result[i +j] 的值直接连进位一起保存到 result[i + j] 中。为什么能这样做呢,因为下次计算 num1[i] * num2[j - 1] 的时候(注意我们是从后往前遍历),会把 result[i + j]和 low 相加,进位自然能被处理,这也是这个算法比较重要的地方。

最后的代码:

let multiply = function (num1, num2) {
  if (isNaN(num1) || isNaN(num2)) return '';
  if (num1 === '0' || num2 === '0') return '0';

  let l1 = num1.length,
    l2 = num2.length;

  let result = [];

  for (let i = l1 -1; i >= 0; i--) {
    for (let j = l2 - 1; j >= 0; j--) {
      let index1 = i + j;
      let index2 = i + j + 1;

      let product = num1[i] * num2[j] + (result[index2] || 0);
      result[index2] = product % 10;
      result[index1] = Math.floor(product / 10) + (result[index1] || 0);
    }
  }
  return result.join('').replace(/^0+/, '');
}

console.log(multiply('123', '234')) //28782

代码中加了两个判断:是否是合法数字,如果有一个值为 0 则直接返回 0。注意最后要判断得到的结果是否开头有 0,如果有则要去掉,这里用的正则表达式。

总结

到此这篇关于JavaScript大数相加相乘的实现方法的文章就介绍到这了,更多相关JavaScript大数相加相乘内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
jQuery load方法用法集锦
Dec 06 Javascript
JavaScript实现x秒后自动跳转到一个页面
Jan 03 Javascript
改变隐藏的input中value的值代码
Dec 30 Javascript
JQuery包裹DOM节点的方法
Jun 11 Javascript
JS提交form表单实例分析
Dec 10 Javascript
js+canvas绘制五角星的方法
Jan 28 Javascript
浅谈json取值(对象和数组)
Jun 24 Javascript
jQuery实现页面下拉100像素出现悬浮窗口的方法
Sep 05 Javascript
javascript数组去重方法分析
Dec 15 Javascript
Vue一次性简洁明了引入所有公共组件的方法
Nov 28 Javascript
如何在Express4.x中愉快地使用async的方法
Nov 18 Javascript
vue 使用rules对表单字段进行校验的步骤
Dec 25 Vue.js
vue任意关系组件通信与跨组件监听状态vue-communication
Oct 18 #Javascript
vscode+gulp轻松开发小程序的完整步骤
Oct 18 #Javascript
详解VUE中的插值( Interpolation)语法
Oct 18 #Javascript
vue自定义树状结构图的实现方法
Oct 18 #Javascript
axios封装与传参示例详解
Oct 18 #Javascript
详解如何使用React Hooks请求数据并渲染
Oct 18 #Javascript
js中复选框的取值及赋值示例详解
Oct 18 #Javascript
You might like
PHP中$_SERVER的详细参数与说明
2008/07/29 PHP
PHP自动选择 连接本地还是远程数据库
2010/12/02 PHP
php setcookie(name, value, expires, path, domain, secure) 参数详解
2013/06/28 PHP
避免Smarty与CSS语法冲突的方法
2015/03/02 PHP
WIN8.1下搭建PHP5.6环境
2015/04/29 PHP
Yii2 如何在modules中添加验证码的方法
2017/06/19 PHP
jquery的颜色选择插件实例代码
2008/10/02 Javascript
JS组件系列之Bootstrap table表格组件神器【终结篇】
2016/05/10 Javascript
jQuery实现点击查看大图并以弹框的形式居中
2016/08/08 Javascript
chrome浏览器如何断点调试异步加载的JS
2016/09/05 Javascript
JS实现AES加密并与PHP互通的方法分析
2017/04/19 Javascript
AngularJS实现的JSONP跨域访问数据传输功能详解
2017/07/20 Javascript
使用JavaScript实现点击循环切换图片效果
2017/09/03 Javascript
vue 组件中添加样式不生效的解决方法
2018/07/06 Javascript
Vue cli构建及项目打包以及出现的问题解决
2018/08/27 Javascript
vueJs实现DOM加载完之后自动下拉到底部的实例代码
2018/08/31 Javascript
详解如何用typescript开发koa2的二三事
2018/11/13 Javascript
ESLint 是如何检查 .vue 文件的
2020/11/30 Vue.js
[00:35]DOTA2上海特级锦标赛 VP战队宣传片
2016/03/04 DOTA
[00:10]DOTA2全国高校联赛速递
2018/05/30 DOTA
python3使用urllib模块制作网络爬虫
2016/04/08 Python
python字符串,数值计算
2016/10/05 Python
【Python】Python的urllib模块、urllib2模块批量进行网页下载文件
2016/11/19 Python
Python入门_浅谈for循环、while循环
2017/05/16 Python
分数霸榜! python助你微信跳一跳拿高分
2018/01/08 Python
python得到windows自启动列表的方法
2018/10/14 Python
PyTorch的Optimizer训练工具的实现
2019/08/18 Python
tensorflow实现读取模型中保存的值 tf.train.NewCheckpointReader
2020/02/10 Python
Shopee印度尼西亚:东南亚与台湾市场最大电商平台
2018/06/17 全球购物
大学生联谊活动策划书(光棍节)
2014/10/10 职场文书
担保书格式
2015/01/20 职场文书
2015国际残疾人日活动总结
2015/03/24 职场文书
2015年学校保卫部工作总结
2015/05/11 职场文书
水知道答案观后感
2015/06/08 职场文书
毕业生自我鉴定范文
2019/05/13 职场文书
使用Django实现商城验证码模块的方法
2021/06/01 Python