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 相关文章推荐
javascript eval函数深入认识
Feb 21 Javascript
jquery中ajax学习笔记4
Oct 16 Javascript
Extjs中TabPane如何嵌套在其他网页中实现思路及代码
Jan 27 Javascript
javascript获取鼠标位置部分的实例代码(兼容IE,FF)
Aug 05 Javascript
javascript去除字符串中所有标点符号和提取纯文本的正则
Jun 07 Javascript
JS替换字符串中空格方法
Apr 17 Javascript
jQuery实现模拟marquee标签效果
Jul 14 Javascript
jQuery 检查某个元素在页面上是否存在实例代码
Oct 27 Javascript
Js判断H5上下滑动方向及滑动到顶部和底部判断的示例代码
Nov 15 Javascript
详谈vue+webpack解决css引用图片打包后找不到资源文件的问题
Mar 06 Javascript
使用xampp将angular项目运行在web服务器的教程
Sep 16 Javascript
vue3使用vuedraggable实现拖拽功能
Apr 06 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 header Content-Type类型小结
2011/07/03 PHP
php实现图形显示Ip地址的代码及注释
2014/01/20 PHP
简单介绍win7下搭建apache+php+mysql开发环境
2015/08/06 PHP
php 从指定数字中获取随机组合的简单方法(推荐)
2017/04/05 PHP
PHP正则匹配操作简单示例【preg_match_all应用】
2017/07/10 PHP
ThinkPHP3.2.3框架Memcache缓存使用方法实例总结
2019/04/15 PHP
javascript 框架小结 个人工作经验
2009/06/13 Javascript
JS 文件本身编码转换 图文教程
2009/10/12 Javascript
Microsfot .NET Framework4.0框架 安装失败的解决方法
2013/08/14 Javascript
jQuery实现多按钮单击变色
2014/11/27 Javascript
浅谈Node.js:理解stream
2016/12/08 Javascript
vue2.0结合DataTable插件实现表格动态刷新的方法详解
2017/03/17 Javascript
JS+HTML5实现图片在线预览功能
2017/07/22 Javascript
ReactNative页面跳转Navigator实现的示例代码
2017/08/02 Javascript
浅谈gulp创建完整的项目流程
2017/12/20 Javascript
JavaScript原型链与继承操作实例总结
2018/08/24 Javascript
webpack4 SCSS提取和懒加载的示例
2018/09/03 Javascript
老生常谈JavaScript获取CSS样式的方法(兼容各浏览器)
2018/09/19 Javascript
在Vue项目中取消ESLint代码检测的步骤讲解
2019/01/27 Javascript
js回文数的4种判断方法示例
2019/06/04 Javascript
一个手写的vue放大镜效果
2019/08/09 Javascript
基于vue实现探探滑动组件功能
2020/05/29 Javascript
Python中使用语句导入模块或包的机制研究
2015/03/30 Python
详解Python3中字符串中的数字提取方法
2017/01/14 Python
django ajax json的实例代码
2018/05/29 Python
python根据url地址下载小文件的实例
2018/12/18 Python
Spring http服务远程调用实现过程解析
2020/06/11 Python
Python 利用flask搭建一个共享服务器的步骤
2020/12/05 Python
怎样实现H5+CSS3手指滑动切换图片的示例代码
2019/05/05 HTML / CSS
奥地利顶级内衣丝袜品牌英国站:Wolford英国
2016/08/29 全球购物
I.T集团香港官方商城:ITeSHOP.com Hong Kong
2019/02/15 全球购物
戴尔马来西亚官网:Dell Malaysia
2020/05/02 全球购物
成人高等教育毕业生自我鉴定
2013/10/22 职场文书
工商管理毕业生推荐信
2013/12/24 职场文书
我的五年职业生涯规划
2014/01/23 职场文书
优秀毕业生推荐信范文
2014/03/07 职场文书