前言:
针对于小数精度问题,本次我们主要推荐两种方式,一种是简单的函数封装,一种是使用第三方库big.js。
方法一:
自封装函数搭配parseFloat和toFixed解决小数精度问题,仅适用于解决一般性小数精度问题,适用于项目中小数问题比较少的项目。
/**
* @description: 处理小数精度
* @param {*} value 需要格式化的数字
* @param {*} fixedNum 保留的小数位数,默认为2
* @param {*} multiple 乘数,默认为1
* @return {*}
*/
export const handleDecimalPrecision = (value, fixedNum = 2, multiple = 1) => {
return parseFloat((value * multiple).toFixed(fixedNum))
}
测试用例:
(传倍数multiple 是为了展示成百分比,比如30%)
0.1 + 0.2 //0.30000000000000004
handleDecimalPrecision(0.1 + 0.2) //0.3
handleDecimalPrecision(0.1 + 0.2,1,100) //30 传倍数multiple 是为了展示成百分比,比如30%
方法二:
使用第三方库big.js 。适用于精度问题比较多的项目,长期性解决精度问题。以下我们将展示一些常见的使用范围的场景,其他的深冷需求可移步至官方文档查看。
big.js特点
- 简单的API
- 比Java的BigDecimal更快、更小、更易于使用
- 复制JavaScript数字的toExponential、toFixed和toPrecision方法
- 可以访问的十进制浮点格式存储值
- 全面的文档和测试集
- 没有依赖关系,相对独立
- 仅使用ECMAScript 3,无兼容性问题
安装big.js
npm install big.js -S
引入big.js
<script>
import Big from 'big.js'
</script>
示例(以vue为例):
code:
<template>
<div class="app-container">
<div>小数精度</div>
<div>未处理 : 0.1 + 0.2 = {{sum_orgin}}</div>
<div>bigjs处理 : 0.1 + 0.2 = {{sum_bigjs}}</div>
</div>
</template>
<script setup>
import Big from 'big.js'
const num1 = 0.1
const num2 = 0.2
const sum_orgin = num1.value + num2.value
const sum_bigjs = Big(num1.value).plus(Big(num2.value))
</script>
效果图:
创建Big number数据
const num1 = Big(0.1)
或者
const num2 = new Big(0.2)
加法精度问题处理 - plus
0.1 + 0.2 //0.30000000000000004
0.7 + 0.1 //0.7999999999999999
0.2 + 0.4 //0.6000000000000001
Big(0.1).plus(Big(0.2)) //0.3
Big(0.1).plus(Big(0.24)) //0.34
减法精度问题 - minus
0.3 - 0.2 //0.09999999999999998
1.5 - 1.2 //0.30000000000000004
Big(0.3).minus(Big(0.2)) //0.1
乘法精度问题 - times
19.9 * 100 //1989.9999999999998
0.8 * 3 //2.4000000000000004
35.41 * 100 //3540.9999999999995
Big(19.9).times(Big(100)) //1990
除法精度问题 - div
0.3 / 0.1 //2.9999999999999996
0.69 / 10 //0.06899999999999999
Big(0.3).div(Big(0.1)) //3
保留小数位数(四舍五入) - round
1 / 3 //0.3333333333333333
Big(1).div(Big(3)).round(3) //0.333
big.js运算符说明
运算符 | 说明 |
abs | 取绝对值 |
cmp | compare的缩写,即比较函数 |
div | 除法 |
eq | equal的缩写,即相等比较 |
gt | 大于 |
gte | 小于等于,e表示equal |
lt | 小于 |
lte | 小于等于,e表示equal |
minus | 减法 |
mod | 取余 |
plus | 加法 |
pow | 次方 |
prec | 按精度舍入,参数表示整体位数 |
round | 按精度舍入,参数表示小数点后位数 |
sqrt | 开方 |
times | 乘法 |
toExponential | 转化为科学计数法,参数代表精度位数 |
toFied | 补全位数,参数代表小数点后位数 |
toJSON/toString | 转化为字符串 |
toPrecision | 按指定有效位数展示,参数为有效位数 |
toNumber | 转化为JavaScript中number类型 |
valueOf | 包含负号(如果为负数或者-0)的字符串 |
拓展
小数为什么失去了精度?
在计算机中,小数(浮点数)的表示和存储方式决定了它们可能会失去精度。这是因为计算机使用二进制(0和1)来表示数字,而二进制无法精确表示某些十进制小数。例如,十进制的 0.1 在二进制中是一个无限循环小数,无法精确表示。这种表示上的限制导致了小数在计算机中的精度问题。
原因:
二进制表示:计算机使用二进制(0和1)来表示数字。然而,二进制无法精确表示某些十进制小数,例如 0.1、0.2、0.3 等。这些小数在二进制中是无限循环小数,无法精确表示。
存储限制:计算机中的浮点数使用有限的位数来表示,包括符号位、指数位和尾数位。这种有限的表示方式限制了浮点数的精度。
舍入误差:在将十进制小数转换为二进制浮点数时,可能会出现舍入误差。这种舍入误差会导致小数的精度下降。
解决方法:
使用定点数:定点数是一种特殊的浮点数表示方式,它将小数点固定在某个位置。使用定点数可以避免二进制表示带来的精度问题,但需要手动处理小数点的位置。
使用高精度库:一些编程语言提供了高精度库,可以处理大数和浮点数的精确计算。这些库使用更大的位数来表示数字,从而提高了精度。
四舍五入:在计算过程中,可以使用四舍五入等方法来减少舍入误差,提高小数的精度。
使用整数表示:在某些情况下,可以将小数转换为整数来避免精度问题。例如,将 0.01 转换为 1,将 0.02 转换为 2,以此类推。
需要注意的是,虽然上述方法可以减少小数的精度问题,但并不能完全避免。在处理小数时,需要根据具体的应用场景和需求来选择合适的方法。