在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

【讨论】:

不适用于 yx 的所有组合。 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中处理浮点精度[重复]的主要内容,如果未能解决你的问题,请参考以下文章

货币的浮点精度:在 MySQL 查询 vs PHP vs Javascript 中使用“round”函数

C浮点精度[重复]

解决JavaScript浮点数计算精度问题

Pandas df中的浮点精度[重复]

变体浮点到双精度值转换,舍入到小数点后 1 位 [重复]

JavaScript浮点运算,小数点精度