在Javascript中处理浮点精度[重复]
Posted
技术标签:
【中文标题】在Javascript中处理浮点精度[重复]【英文标题】:Dealing with float precision in Javascript [duplicate] 【发布时间】:2012-07-26 14:14:20 【问题描述】:我在 javascript 中有大量数值 y
。我想通过将它们四舍五入到最接近的x
倍数来对它们进行分组,并将结果转换为字符串。
如何解决烦人的浮点精度问题?
例如:
0.2 + 0.4 = 0.6000000000000001
我尝试过的两件事:
>>> y = 1.23456789
>>> x = 0.2
>>> parseInt(Math.round(Math.floor(y/x))) * x;
1.2000000000000002
和:
>>> y = 1.23456789
>>> x = 0.2
>>> y - (y % x)
1.2000000000000002
【问题讨论】:
这实际上是double
的正常行为,您只是在大多数语言的打印语句中看不到它。你试过四舍五入吗?
您无法真正“绕过”它,因为它是二进制浮点数学系统的内在方面。显然,您的“x”和“y”值都是如此;如果“x”为 0.3,则无法准确表示。 “四舍五入”到任意分数会导致不精确。
那么将y
转换为"1.2"
的另一种方法是什么。
@Jeroen 我相信你已经知道了,但只是为了记录,Math.floor(y)
。
@pilau 会产生 1,而不是 1.2
【参考方案1】:
来自这个帖子:How to deal with floating point number precision in JavaScript?
你有几个选择:
对小数使用特殊的数据类型,例如decimal.js 将结果格式化为一些固定数量的有效数字,如下所示:(Math.floor(y/x) * x).toFixed(2)
将所有数字转换为整数
【讨论】:
“将所有数字转换为整数”,我对此感到疑惑。我们知道,JavaScript 有一个数字类型Number
,一个 IEEE 754 浮点数。如果是这种情况,那么为什么将浮点数转换为整数会起作用(并且确实如此)? JavaScript 是否真的有一个不能通过保留字访问的整数数据类型?
IEEE 754 可以精确地表示最大为 2^50 的整数。因此,如果您在已知范围内工作,则可以缩放值以利用 50 位(或其他)精度,而不是浪费通常为大数字保留的精度。
@richremer 浮点具有精度(对于正常值)不依赖于大小的属性。 - 因此,无论您将其转换为整数(例如将值与某个常数相乘),精度都是相等的。
“有效位数”的位数是使用科学计数法的位数(没有前导或尾随零),它是根据情况选择的。 - toPrecision 的参数似乎是一些有效数字。 - toFixed 用于多个尾随数字。
toFixed() 会将数字转换为字符串。【参考方案2】:
处理这个任务,我首先在x
中找到小数位数,然后相应地对y
进行四舍五入。我会使用:
y.toFixed(x.toString().split(".")[1].length);
它应该将x
转换为字符串,将其拆分到小数点处,找到正确部分的长度,然后y.toFixed(length)
应该根据该长度对y
进行四舍五入。
【讨论】:
这有点问题,x
是一个整数。【参考方案3】:
你可以这样做:
> +(Math.floor(y/x)*x).toFixed(15);
1.2
编辑:最好使用 big.js。
big.js
一个小型、快速、易于使用的任意精度十进制算术库。
>> bigX = new Big(x)
>> bigY = new Big(y)
>> bigY.div(bigX).round().times(bigX).toNumber() // => 1.2
【讨论】:
不适用于y
和 x
的所有组合。
toFixed 返回一个字符串
逐轮替换,+
由 parseFloat 替换,如果可以的话,将 15 替换为较小的数字(toFixed 参数可以基于 x 计算)【参考方案4】:
查看此链接。它对我有很大帮助。
http://www.w3schools.com/jsref/jsref_toprecision.asp
toPrecision(no_of_digits_required)
函数返回一个string
,所以不要忘记使用parseFloat()
函数转换为所需精度的小数点。
【讨论】:
如果你碰巧是这个答案对我投反对票的人,你能解释一下原因吗? (提供的解决方案似乎有效) 基本上问题是这样的,你有 js 数字 y 和 x,你想要 x 的最接近(从 y)倍数。 toPrecision 方法没有帮助,即parseFloat((150).toPrecision(1)) === 200
【参考方案5】:
> var x = 0.1
> var y = 0.2
> var cf = 10
> x * y
0.020000000000000004
> (x * cf) * (y * cf) / (cf * cf)
0.02
快速解决方案:
var _cf = (function()
function _shift(x)
var parts = x.toString().split('.');
return (parts.length < 2) ? 1 : Math.pow(10, parts[1].length);
return function()
return Array.prototype.reduce.call(arguments, function (prev, next) return prev === undefined || next === undefined ? undefined : Math.max(prev, _shift (next)); , -Infinity);
;
)();
Math.a = function ()
var f = _cf.apply(null, arguments); if(f === undefined) return undefined;
function cb(x, y, i, o) return x + f * y;
return Array.prototype.reduce.call(arguments, cb, 0) / f;
;
Math.s = function (l,r) var f = _cf(l,r); return (l * f - r * f) / f; ;
Math.m = function ()
var f = _cf.apply(null, arguments);
function cb(x, y, i, o) return (x*f) * (y*f) / (f * f);
return Array.prototype.reduce.call(arguments, cb, 1);
;
Math.d = function (l,r) var f = _cf(l,r); return (l * f) / (r * f); ;
> Math.m(0.1, 0.2)
0.02
您可以查看完整说明here。
【讨论】:
我的荣幸 :-) Math.m(0.07, 100) => 7.000000000000002 这不行!以上是关于在Javascript中处理浮点精度[重复]的主要内容,如果未能解决你的问题,请参考以下文章