如何处理JavaScript中的浮点数精度?

如何处理JavaScript中的浮点数精度?,javascript,floating-point,Javascript,Floating Point,我有以下虚拟测试脚本: 功能测试(){ var x=0.1*0.2; 文件。编写(x); } test()看一看。如果您想要操作的数字范围很小(例如,货币),那么它可能会解决您的问题。我会将它四舍五入到几个十进制值,这是最简单的解决方案 看一看。如果您想要操作的数字范围很小(例如,货币),那么它可能会解决您的问题。我会将它四舍五入到几个十进制值,这是最简单的解决方案 使用 var x = 0.1*0.2; x =Math.round(x*Math.pow(10,2))/Math.pow(10

我有以下虚拟测试脚本:

功能测试(){
var x=0.1*0.2;
文件。编写(x);
}
test()看一看。如果您想要操作的数字范围很小(例如,货币),那么它可能会解决您的问题。我会将它四舍五入到几个十进制值,这是最简单的解决方案

看一看。如果您想要操作的数字范围很小(例如,货币),那么它可能会解决您的问题。我会将它四舍五入到几个十进制值,这是最简单的解决方案

使用

var x = 0.1*0.2;
 x =Math.round(x*Math.pow(10,2))/Math.pow(10,2);
使用


试试我的智利算术库,你可以看到。
如果你想要更高版本,我可以给你一个。

试试我的chiliadic算术库,你可以看到。
如果您想要一个更高版本,我可以给您一个。

您不能用二进制浮点类型(ECMAScript使用二进制浮点类型来表示浮点值)精确地表示大多数小数。因此,除非您使用任意精度的算术类型或基于十进制的浮点类型,否则没有一个优雅的解决方案。例如,.

您不能用二进制浮点类型(ECMAScript使用二进制浮点类型来表示浮点值)精确地表示大多数小数。因此,除非您使用任意精度的算术类型或基于十进制的浮点类型,否则没有一个优雅的解决方案。例如,.

你只需要决定你到底想要多少位小数-不能既吃蛋糕又吃蛋糕:-)

随着每一次进一步的操作,数值误差都会不断累积,如果你不尽早切断它,它只会越来越大。数字库显示的结果看起来很干净,只需在每一步切断最后2位数字,数字协处理器也有“正常”和“完整”长度,原因相同。Cuf-offs对于处理器来说很便宜,但是对于脚本来说非常昂贵(乘法、除法和使用pov(…)。好的数学库会为你提供一个截断点(x,n)

因此,至少您应该使用pov(10,n)使全局var/恒定-这意味着您决定了所需的精度:-),然后执行以下操作:

你也可以继续做数学运算,最后只截取数据——假设你只显示结果,而不做if-s。如果您能做到这一点,那么.toFixed(…)可能会更有效


如果您正在进行If-s/比较,并且不想减少,那么您还需要一个小常量,通常称为eps,它比最大预期误差高一个小数位。假设您的截止值是最后两位小数-那么您的每股收益在最后一位的第三位有1(第三位最不显著),您可以使用它来比较结果是否在预期的每股收益范围内(0.02-每股收益<0.1*0.2<0.02+每股收益).

你只需要决定你到底想要多少个十进制数字-不能既吃蛋糕又吃蛋糕:-)

随着每一次进一步的操作,数值误差都会不断累积,如果你不尽早切断它,它只会越来越大。数字库显示的结果看起来很干净,只需在每一步切断最后2位数字,数字协处理器也有“正常”和“完整”长度,原因相同。Cuf-offs对于处理器来说很便宜,但是对于脚本来说非常昂贵(乘法、除法和使用pov(…)。好的数学库会为你提供一个截断点(x,n)

因此,至少您应该使用pov(10,n)使全局var/恒定-这意味着您决定了所需的精度:-),然后执行以下操作:

你也可以继续做数学运算,最后只截取数据——假设你只显示结果,而不做if-s。如果您能做到这一点,那么.toFixed(…)可能会更有效


如果您正在进行If-s/比较,并且不想减少,那么您还需要一个小常量,通常称为eps,它比最大预期误差高一个小数位。假设您的截止值是最后两位小数-那么您的eps在最后一位的第三位有1(第三位最不显著),您可以使用它来比较结果是否在预期的eps范围内(0.02-eps<0.1*0.2<0.02+eps)。

您正在寻找一个用于JavaScript的
sprintf
实现,这样您就可以以您期望的格式写出带有小错误的浮点(因为它们是以二进制格式存储的)

试试看,你会这样称呼它:

var yourString = sprintf("%.2f", yourNumber);
将数字打印为小数点后两位的浮点数


如果您不想包含更多的文件,而只是为了将浮点舍入到给定的精度,那么也可以将其用于显示目的

您正在寻找一个JavaScript的
sprintf
实现,这样您就可以以您期望的格式写出带有小错误的浮点值(因为它们是以二进制格式存储的)

试试看,你会这样称呼它:

var yourString = sprintf("%.2f", yourNumber);
将数字打印为小数点后两位的浮点数


如果您不想包含更多的文件,而只是为了将浮点舍入到给定的精度,那么也可以将其用于显示目的

你说得对,原因是浮点数的精度有限。将有理数存储为两个整数的除法,在大多数情况下,您将能够在不损失任何精度的情况下存储数字。在打印时,您可能希望将结果显示为分数。有了我提出的表述,它就变得微不足道了


当然,这对非理性数字没有多大帮助。但是,您可能希望优化您的计算,使其产生的问题最少(例如,检测像
sqrt(3)^2)
您是对的,原因是浮点数的精度有限。将有理数存储为两个整数的除法,在大多数情况下,您将能够在不损失任何精度的情况下存储数字。Whe
var times = function (a, b) {
    return Math.round((a * b) * 100)/100;
};
var fpFix = function (n) {
    return Math.round(n * 100)/100;
};

fpFix(0.1*0.2); // -> 0.02
var fpArithmetic = function (op, x, y) {
    var n = {
            '*': x * y,
            '-': x - y,
            '+': x + y,
            '/': x / y
        }[op];        

    return Math.round(n * 100)/100;
};
fpArithmetic('*', 0.1, 0.2);
// 0.02

fpArithmetic('+', 0.1, 0.2);
// 0.3

fpArithmetic('-', 0.1, 0.2);
// -0.1

fpArithmetic('/', 0.2, 0.1);
// 2
function multFloats(a,b){
  var atens = Math.pow(10,String(a).length - String(a).indexOf('.') - 1), 
      btens = Math.pow(10,String(b).length - String(b).indexOf('.') - 1); 
  return (a * atens) * (b * btens) / (atens * btens); 
}
function strip(number) {
    return (parseFloat(number).toPrecision(12));
}
num = .01 + .06;  // yields 0.0699999999999
rnum = round(num,12); // yields 0.07
> 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
function test(){
    var x = 0.1 * 0.2;
    document.write(Number(x).toFixed(2));
}
test();
x = Math.round(x*100);
// I only need 2 decimal places, if i needed 3 I would use 1,000, etc.
x = x / 100;
xB = new BigNumber(x);
function dec( num )
{
    var p = 100;
    return Math.round( num * p ) / p;
}
a = 0.1;
b = 0.2;

a + b = 0.30000000000000004;

c = parseFloat((a+b).toFixed(2));

c = 0.3;

a = 0.3;
b = 0.2;

a - b = 0.09999999999999998;

c = parseFloat((a-b).toFixed(2));

c = 0.1;
0.1 + 0.2 === 0.3 // which returns false
function epsEqu(x, y) {
    return Math.abs(x - y) < Number.EPSILON;
}
console.log(epsEqu(0.1+0.2, 0.3)); // true
function precisionRound(number, precision) {
  var factor = Math.pow(10, precision);
  return Math.round(number * factor) / factor;
}
0.1 * 0.2                                // 0.020000000000000004
x = new Decimal(0.1)
y = x.times(0.2)                          // '0.2'
x.times(0.2).equals(0.2)                  // true
function evalMathematicalExpression(a, b, op) {
    const smallest = String(a < b ? a : b);
    const factor = smallest.length - smallest.indexOf('.');

    for (let i = 0; i < factor; i++) {
        b *= 10;
        a *= 10;
    }

    a = Math.round(a);
    b = Math.round(b);
    const m = 10 ** factor;
    switch (op) {
        case '+':
            return (a + b) / m;
        case '-':
            return (a - b) / m;
        case '*':
            return (a * b) / (m ** 2);
        case '/':
            return a / b;
    }

    throw `Unknown operator ${op}`;
}

(0.1).toPrecision(100) ->
0.1000000000000000055511151231257827021181583404541015625000000000000000000000000000000000000000000000

(0.1+0.2).toPrecision(100) ->
0.3000000000000000444089209850062616169452667236328125000000000000000000000000000000000000000000000000
10**Math.floor(53 * Math.log10(2)) // 1e15
Math.round((0.2+0.1) * 1e15 ) / 1e15
0.3
(Math.round((0.2+0.1) * 1e15 ) / 1e15).toPrecision(100)
0.2999999999999999888977697537484345957636833190917968750000000000000000000000000000000000000000000000
function roundNumberToHaveANiceDefaultStringRepresentation(num) {

    const integerDigits = Math.floor(Math.log10(Math.abs(num))+1);
    const mult = 10**(15-integerDigits); // also consider integer digits
    return Math.round(num * mult) / mult;
}