前端:金额高精度处理

Decimal 是什么

想必大家在用js 处理 数字的 加减乘除的时候,或许都有遇到过 精度不够 的问题,还有那些经典的面试题 0.2+0.1 !== 0.3,

至于原因,那就是 js 计算底层用的是 IEEE 754 ,精度上有限制,

那么Decimal.js 就是帮助我们解决 js中的精度失准的问题。

原理

  • 它的原理就是将数字用字符串表示,字符串在计算机中可以说是无限的。
  • 并使用基于字符串的算术运算,以避免浮点数运算中的精度丢失。它使用了一种叫做十进制浮点数算术(Decimal Floating Point Arithmetic)的算法来进行精确计算。
  • 具体来说,decimal.js库将数字表示为一个字符串,其中包含整数部分、小数部分和一些其他的元数据。它提供了一系列的方法和运算符,用于执行精确的加减乘除、取模、幂运算等操作。

精度丢失用例

javascript 复制代码
const a = 31181.82
const b = 50090.91
console.log(a+b) //81272.73000000001

Decimal 的引入 与 加减乘除

如何引入

javascript 复制代码
npm install --save decimal.js  // 安装
import Decimal from "decimal.js"  // 具体文件中引入
javascript 复制代码
// 加

let a = 1
let b = 6 
// a 与 b 可以是 任何类型,Decimal 内部会自己处理兼容
// 下面两种都可以 可以带 new 也不可以不带 new(推荐带new)
let res = new Decimal(a).add(new Decimal(b)) 
let res = Decimal(a).add(Decimal(b))


// 减

js 代码解读复制代码let a = "4"
let b = "8"
// a 与 b 可以是 任何类型,Decimal 内部会自己处理兼容
// 下面两种都可以 可以带 new 也不可以不带 new
let res = new Decimal(a).sub(new Decimal(b)) 
let res = Decimal(a).sub(Decimal(b))


// 乘

js 代码解读复制代码let a = 1
let b = 6 
// a 与 b 可以是 任何类型,Decimal 内部会自己处理兼容
// 下面两种都可以 可以带 new 也不可以不带 new
let res = new Decimal(a).mul(new Decimal(b)) 
let res = Decimal(a).mul(Decimal(b))


// 除

js 代码解读复制代码let a = 1
let b = 6 
// a 与 b 可以是 任何类型,Decimal 内部会自己处理兼容
// 下面两种都可以 可以带 new 也不可以不带 new
let res = new Decimal(a).div(new Decimal(b)) 
let res = Decimal(a).div(Decimal(b))

注意

上面的结果是 一个 Decimal 对象,你可以转换成 Number 或则 String

javascript 复制代码
let res = Decimal(a).div(Decimal(b)).toNumber()  // 结果转换成 Number
let res = Decimal(a).div(Decimal(b)).toString()  // 结果转换成 String

关于保存几位小数相关

javascript 复制代码
//查看有几位小数 (注意不计算 小数点 最后 末尾 的 0)
y = new Decimal(987000.000)
y.sd()                                   // '3' 有效位数
y.sd(true)                               // '6' 总共位数

// 保留 多少个位数 (小数位 会补0)
x = 45.6
x.toPrecision(5)                         // '45.600'

// 保留 多少位有效位数(小数位 不会补0,是计算的有效位数)
x = new Decimal(9876.5)
x.toSignificantDigits(6)                 // '9876.5' 不会补0 只是针对有效位数

// 保留几位小数 , 跟 js 中的 number 一样
toFixed
x = 3.456
// 向下取整
x.toFixed(2, Decimal.ROUND_DOWN)  // '3.45' (舍入模式 向上0 向下1 四舍五入 4,7)
// 向上取整
Decimal.ROUND_UP 

//四舍五入
ROUND_HALF_UP //(主要)

// 使用例子
let num2 = 0.2
let num3 = 0.1
let res = new Decimal(num2).add(new Decimal(num3)).toFixed(2, Decimal.ROUND_HALF_UP)
console.log(res); //返回值是字符串类型

超过 javascript 允许的数字

如果使用超过 javascript 允许的数字的值,建议传递字符串而不是数字,以避免潜在的精度损失。

javascript 复制代码
new Decimal(1.0000000000000001); // '1'
new Decimal(88259496234518.57); // '88259496234518.56'
new Decimal(99999999999999999999); // '100000000000000000000'

new Decimal(2e308); // 'Infinity'
new Decimal(1e-324); // '0'

new Decimal(0.7 + 0.1); // '0.7999999999999999'

可读性

与 JavaScript 数字一样,字符串可以包含下划线作为分隔符以提高可读性。

javascript 复制代码
x = new Decimal("2_147_483_647");

其它进制的数字

如果包含适当的前缀,则也接受二进制、十六进制或八进制表示法的字符串值。

javascript 复制代码
x = new Decimal("0xff.f"); // '255.9375'
y = new Decimal("0b10101100"); // '172'
z = x.plus(y); // '427.9375'

z.toBinary(); // '0b110101011.1111'
z.toBinary(13); // '0b1.101010111111p+8'

x = new Decimal(
  "0b1.1111111111111111111111111111111111111111111111111111p+1023"
);
// '1.7976931348623157081e+308'
相关推荐
xcs194056 小时前
前端 vue 的前端页面debugger 进不去
前端·javascript·vue.js
明月_清风7 小时前
Deno 终局来了:从挑战 Node 到被 Cloudflare 收编
前端·后端·node.js
Csvn8 小时前
框架性能优化
前端
回眸&啤酒鸭10 小时前
【回眸】OpenSwarm 多智能体协作系统实战指南
大数据·前端·人工智能
用户693717500138410 小时前
2026,程序员的时代拐点到了
android·前端·后端
大龄秃头程序员10 小时前
一次 iBeacon + BLE 无感解锁方案的实现记录
前端
小兔子10 小时前
Python 的 GIL 与 free-threading:3.13 之后「去 GIL」走到哪一步了
前端
IT_陈寒10 小时前
SpringBoot自动配置差点让我加班到凌晨
前端·人工智能·后端
guslegend11 小时前
脚手架原理与本地调试:从 bin 软链接到 npm link
前端·npm·node.js·脚手架·前端工程化
小宋102111 小时前
A2UI从零实战:Agent安全生成交互界面与事件回传
javascript·人工智能·安全·交互