利用Math.js解决JS计算小数精度丢失问题

作者:LPieces 时间:2024-04-29 13:44:04 

缘由

最近在做公司的一个点餐H5项目需要前端动态计算用户选的商品的总价(单价*数量)和购物车的总价格时发现关于 JavaScript 浮点数计算精度不准确问题。在控制台输入0.1+0.2也能发现此问题。

// 加法
   0.1 + 0.2 = 0.30000000000000004
   0.7 + 0.1 = 0.7999999999999999
   0.2 + 0.4 = 0.6000000000000001

// 减法
   1.5 - 1.2 = 0.30000000000000004
   0.3 - 0.2 = 0.09999999999999998

// 乘法
   19.9 * 100 = 1989.9999999999998
   0.8 * 3 = 2.4000000000000004
   35.41 * 100 = 3540.9999999999995

// 除法
   0.3 / 0.1 = 2.9999999999999996
   0.69 / 10 = 0.06899999999999999

问题的原因

为什么 0.1+0.2 JS加不了? 产生浮点数计算精度不准确的原因: 在计算机角度,计算机算的是二进制,而不是十进制。二进制后变成了无线不循环的数,而计算机可支持浮点数的小数部分可支持到52位,所有两者相加,在转换成十进制,得到的数就不准确了,加减乘除运算原理一样。

十进制二进制
0.10.0001 1001 1001 1001 ...
0.20.0011 0011 0011 0011 ...
0.30.0100 1100 1100 1100 ...
0.40.0110 0110 0110 0110 ...
0.50.1
0.60.1001 1001 1001 1001 ...

所以两者相加之后得到这么一串 0.0100110011001100110011001100110011001100110011001100 因浮点数小数位的限制而截断的二进制数字,这时候,我们再把它转换为十进制,就成了 0.30000000000000004。

最通俗的解释

比如一个数 1÷3=0.33333333...... 大家都知道3会一直无限循环,数学可以表示,但是计算机要存储,方便下次取出来再使用,但0.333333...... 这个数 无限循环,你让计算机怎么存储?计算机再大的内存它也存不下,对吧! 所以不能存储一个相对于数学来说的值,只能存储一个近似值,所以当计算机存储后再取出来用时就会出现精度问题。

解决方案 - Math.js

对于任意精度的计算,math.js 支持BigNumber 数据类型。

安装

npm install mathjs

请注意,在 TypeScript 项目中使用 mathjs 时,您还必须安装类型定义文件:npm install @types/mathjs.

封装

import * as math from 'mathjs';
export default {
   // 加
add(num1,num2){
return math.add(math.bignumber(num1),math.bignumber(num2));
},
// 乘
multiply(num1,num2){
return math.multiply(math.bignumber(num1),math.bignumber(num2));
},
// 减
subtract(num1,num2){
return math.subtract(math.bignumber(num1),math.bignumber(num2));
},
// 除
divide(num1,num2){
return math.divide(math.bignumber(num1),math.bignumber(num2));
}
}

使用

import math from './math.js'
let addNum = math.add(3,2); // 5
let mulNum = math.multiply(3,2); // 6
let subNum = math.subtract(3,2); // 1
let divNum = math.divide(3,2); // 1.5

附:math.js 大数功能

<script type="text/javascript">
// functions and constants
console.log('mathjs BigNumber eg')
print(math.add(math.bignumber(0.1), math.bignumber(0.2))) // 加法 BigNumber, 0.3
print(math.subtract(math.bignumber(1), math.bignumber(0.9))) // 减法 BigNumber, 0.1
print(math.multiply(math.bignumber(4.10), math.bignumber(100))) // 乘法 BigNumber, 0.1
print(math.ceil(math.bignumber(6.10)/ math.bignumber(0.1)));   //除法 向上取整 61
print(math.floor(math.bignumber(6.10)/ math.bignumber(0.1)));   //除法 向下取整 61
print(math.round(math.bignumber(6.10)/ math.bignumber(0.1)));   // 除法 四舍五入 61
/**
* Helper function to output a value in the console. Value will be formatted.
* @param {*} value
*/
function print (value) {
 const precision = 14
 console.log(math.format(value, precision))
}
</script>

来源:https://juejin.cn/post/6980282248104771615

标签:math.js,小数,精度
0
投稿

猜你喜欢

  • PyQt5实现界面(页面)跳转的示例代码

    2023-06-21 18:48:43
  • python实现一个简单的并查集的示例代码

    2023-05-15 17:14:54
  • node实现mock-plugin中间件的方法

    2024-05-13 10:05:59
  • Django2.1.7 查询数据返回json格式的实现

    2023-09-28 09:54:20
  • 基于Python获取照片的GPS位置信息

    2021-02-25 03:32:00
  • js substr支持中文截取函数代码(中文是双字节)

    2024-04-10 10:44:58
  • python实现多线程端口扫描

    2021-07-06 03:27:26
  • 如何利用Python开发一个简单的猜数字游戏

    2022-05-21 20:38:08
  • 语言编程花絮内建构建顺序示例详解

    2023-11-04 09:42:12
  • python 遍历磁盘目录的三种方法

    2021-10-15 06:36:14
  • Python爬虫运用正则表达式的方法和优缺点

    2023-04-03 22:09:21
  • 基于python和flask实现http接口过程解析

    2022-06-01 11:46:36
  • 用python爬取租房网站信息的代码

    2022-04-30 07:03:38
  • Python3访问并下载网页内容的方法

    2022-11-12 06:08:39
  • Python简单网络编程示例【客户端与服务端】

    2023-12-07 10:26:55
  • 解决DataFrame排序sort的问题

    2023-07-04 15:37:35
  • python多线程用法实例详解

    2023-02-08 11:24:03
  • 基于Python的EasyGUI学习实践

    2021-09-05 10:54:55
  • 用Python在Excel里画出蒙娜丽莎的方法示例

    2023-12-18 02:59:21
  • python列表元素拼接成字符串的4种方法

    2021-10-02 23:59:59
  • asp之家 网络编程 m.aspxhome.com