nstr.vercel.app/
一个处理数字显示问题的 JS 库。
尤其是在处理有小数点的数字时会很有用。

好东西, 看看去

很有用,感谢分享

好用,支持!

确实 looks good, 源码才 113 行,实现方法很巧妙。

console.log(new Decimal('0.1').plus(new Decimal('0.2')).toString())
vs
console.log(nstr(0.1+0.2))

因为设计使然,超过 4 位(可自行设定)的 9 和 0 会被认为是噪音然后截断处理,不适用多位小数严格计算场景,其他场景都不错。

另外如果有严格小数计算需求, 可以考虑 bignumber.js ,精度极高无任何误差, 在我以前某无聊的变态超大数计算项目里验证过, 小数点后精度 9999 无压力

好东西

我看样例都看不懂
显示不了 451.79 ?
451.79999999456789 = 451.8
451.78999999456789 = 451.78
451.77999999456789 = 451.78
451.76999999456789 = 451.77

不推荐这个库

推荐使用 decimal.js 实现精确的计算。
而不是计算以后猜数字

0.3 - 0.1 // 0.19999999999999998
x = new Decimal(0.3)
x.minus(0.1) // '0.2'
x // '0.3'

#7
这个库只是用来处理 0.1+0.2=0.30000000000000004 这种问题的,让简单的浮点计算适合人类阅读
产生这种问题的浮点数都有个共同的特点:一连串的 0 或者 9 ,所以这个库就检测 0/9 连续出现的次数,超过判断条件后截断全部 0/9 最后简单处理一下进位
需要多位小数严谨计算的应该用 decimal.js, bignumber.js
这个库我觉得已经说得很清楚了,nstr ,就是数字转字符串,字符串是用来看的不是计算的,不需要严谨小数点计算的前端纯展示场景非常非常多

为啥不用成熟的高精度库呢,这个库的规则太简单粗暴了

#10 我觉得我在 4#的例子已经很有说服力了,在你想展示几个浮点数的计算结果时,你希望写的是
new Decimal(a).plus(new Decimal(b).times(new Decimal(c))).minus(new Decimal(d))
还是
nstr(a+b*c-d)

有用!

没看懂啊 451.78999999456789 = 451.78 为什么没有进位。。

#13 研究了一下
github.com/shuding/nstr/blob/main/src/index.ts#L64-L77
进位失败是因为
451.78+0.01 = 451.78999999999996
而不是期望的 451.79
需要一个更稳健的进位方法来解决这个问题

#11 我会在后端做好 let x = new Decimal(a).plus(new Decimal(b).times(new Decimal(c))).minus(new Decimal(d)),然后让前端 {x}

说计算精度需求的都跑偏了,网站里面的示例很清楚了,就是为了解决数字格式化的问题,避免因为精度误差导致显示的数字过长或过早使用科学计数法.

不过 100 多行还是有点多了,网站的对比看下来,toFixed 其实很符合要求,只是不会移除尾部 0 ,那么其实再替换下尾部 0 就够了,一行解决
200.0003.toFixed(3).replace(/(.?|(?<=.\d+))0+$/,'')
(?<=.\d+) 就是确保处于小数部分,避免移除了整数部分的尾部 0 ,可能还有其它边界情况没考虑,差不多这个意思。

适合数据可视化上数字展示

#14 我去提了个 PR

#16
我以前项目也写过类似的东西

function n_str(
 value: number,
 options: { fractionDigits?: number } = {},
): string {
 const { fractionDigits = 3 } = options
 const str = value.toFixed(fractionDigits).replace(/(\.?|(?<=\.\d+))0+$/, '')
 return str === '-0' ? '0' : str
}

toFixed()的问题是无法智能判断精度,需要传入参数指定精度
nstr(1.123456) -> 1.123456
n_str(1.123456) -> 1.123
n_str(1.123456, { fractionDigits: 6 }) -> 1.123456
这里的难点是无法简单判断出浮点数计算的小数位数,比如 0.1+0.2 ,人类都知道应该是 1 位小数点,但是如何从 0.30000000000000004 解析出来,还有科学计数法把这个问题搞得更加复杂,而 nstr 能解决这个问题。手动指定精度 2 行就解决了,为了少写这个参数我不介意在项目里多 install 一个包。

目前 nstr 我测了所有情况,就剩 456.78999999456789=456.78 这个问题,其他的都正常
在 nstr 的方案上使用 toFixed 或许能解决这个问题同时不引入其他边缘情况,例如楼上的 pr
github.com/shuding/nstr/pull/2/commits/4713d6447bc8fd3af2e246e63ea2f0edb8445d07

这个库设计很有问题,0.1+0.2 已经为浮点数了,然后又转字符串,还能将 0.1+0.2 还原为 0.3 。如果你想表示 0.33999999999999998 ,它会给你转 0.34 ,结果就是 0.33999999999999998==0.34 这么做,明显有问题

#20
0.3399999999999999 = 0.34 是预期行为,这个库就是用来做这件事的。
这已经是第四遍回答了,当你需要显示/计算标准浮点/decimal 时,请使用原生 js 或者 decimal.js, bignumber.js 。
#16 已经说的很清楚了,这个库的作用是
解决数字格式化的问题,避免因为精度误差导致显示的数字过长或过早使用科学计数法
设计上超过一定数量的连续 0 or 9 会直接截断,很显然这样才能实现 0.1 + 0.2 = 0.3 ,而带来的代价就是无法表达含有超过一定数量的连续 0 or 9 。
这个库的适用场景应该是大屏、统计页面等等各种数据可视化,四位以内小数运算是正确的,连续 0 or 9 超过一定次数就会自动四舍五入,严格计算老实去用 decimal.js, bignumber.js ,这只是解决了非严格 decimal 数据的展示问题,让编写显示浮点计算结果的代码更简单易懂适合人类阅读。

#21 可能做法简洁,但是,我不认为是一个好方法,这样会让行为变得模糊起来。小数最佳实战应该是 decimal.js, bignumber.js 等计算完,然后格式化输出,而不是用这个格式化,造成 0.33999999999999998 看起来像 0.34 的不精确问题

#22 怎么还没绕过这个弯,就不是精度的问题。会取近似值的,epsilon 都远远大于精度误差,根本没必要上高精度库,高精度库也解决不了显示问题。
就假设我有一个原始就是 0.3000004 的数(不是通过计算得来的,可能是网络,可能是可视化的数据集,总之这个数字本身就是这个形式),不需要计算,直接显示成人类可读字符串表示,这个情况你用高精度库有什么意义吗