English 中文(简体)
• 如何处理 Java的浮点数字精确度? [复制]
原标题:How to deal with floating point number precision in JavaScript? [duplicate]
  • 时间:2009-09-22 07:34:42
  •  标签:

我有以下试样:

function test() {
  var x = 0.1 * 0.2;
  document.write(x);
}
test();

这将印刷结果<代码>0.0200000004<<>>0>0>,而应仅印刷<代码>0.02<>>。 (如您使用计算器)。 就我所知,这是由于浮动点多重复精确性方面的错误。

是否有很好的解决办法,以便在这种情况下,我获得正确的结果0.02? 我知道,诸如<条码>至条码<>或四舍五入等功能是另一种可能性,但我真的是在没有切割和四舍五入的情况下印制整份编号。 仅想知道,你们当中有一个人是否拥有某种 n子、 solution子的解决办法。

当然,否则,我向大约10位数点左右。

最佳回答

http://floating-point-gui.de/“rel=“noretinger” Floating-Point Guide:

www.un.org/Depts/DGACM/index_spanish.htm 我能做些什么来避免这一问题?

That depends on what kind of calculations you’re doing.

  • If you really need your results to add up exactly, especially when you work with money: use a special decimal datatype.
  • If you just don’t want to see all those extra decimal places: simply format your result rounded to a fixed number of decimal places when displaying it.
  • If you have no decimal datatype available, an alternative is to work with integers, e.g. do money calculations entirely in cents. But this is more work and has some drawbacks.

请注意,第一点只有在你确实需要具体行为的情况下才能适用。 大多数人并不需要,他们只是再次告诫说,他们的方案没有像第1/10号这样的数字来正确工作,而没有认识到,如果出现第1/3号这样的错误,他们甚至会打上同样的link。

如果第一点确实适用于你,则使用,BigDecimal for Javagust/a>或,DecimalJS,实际解决问题,而不是提供不完美的工作。

问题回答

我喜欢Pedro Ladaria的解决办法,并使用类似的东西。

function strip(number) {
    return (parseFloat(number).toPrecision(12));
}

与Pedros方案不同的是,这一办法将四舍五入到0.999.......重复计算,准确将一升/升至最少的一位数。

注:在处理32或64个轨道浮动时,你应使用Preci(7)和Precision(15)取得最佳结果。 见。 问题涉及原因。

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

建议采用的方法是采用纠正因素(多半采用10个适当权力,以便在分类中进行计算)。 例如,在<代码>0.1 * 0.2的情况下,更正系数为10<>。

> 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

我肯定建议使用一个经过测试的图书馆,如。 SinfulJS

你们是否只是从事多重复工作? 如果是这样的话,你就可以利用关于算术的 ne。 这就是。 这就是说,如果我们有<条码>0.123 *0.12。 那么,我们知道,将有5个小数点,因为<代码>0.123<>>> /代码>有3个小数点,<代码>0.12有2个。 因此,如果 Java版给我们一个编号,例如<014760000002。 我们可以安全地四舍五入到第五点,而不担心会失去准确性。

Surprisingly, this function has not been posted yet although others have similar variations of it. It is from the MDN web docs for Math.round(). It s concise and allows for varying precision.

function precisionRound(number, precision) {
    var factor = Math.pow(10, precision);
    return Math.round(number * factor) / factor;
}

console.log(precisionRound(1234.5678, 1));
// expected output: 1234.6

console.log(precisionRound(1234.5678, -1));
// expected output: 1230

var inp = document.querySelectorAll( input );
var btn = document.querySelector( button );

btn.onclick = function(){
  inp[2].value = precisionRound( parseFloat(inp[0].value) * parseFloat(inp[1].value) , 5 );
};

//MDN function
function precisionRound(number, precision) {
  var factor = Math.pow(10, precision);
  return Math.round(number * factor) / factor;
}
button{
display: block;
}
<input type= text  value= 0.1 >
<input type= text  value= 0.2 >
<button>Get Product</button>
<input type= text >

www.un.org/Depts/DGACM/index_spanish.htm UPDATE: Aug/20/2019

只是注意到这一错误。 我认为,由于浮动点精确度错误,与<代码>Math.round()。

precisionRound(1.005, 2) // produces 1, incorrect, should be 1.01

这些条件是正确的:

precisionRound(0.005, 2) // produces 0.01
precisionRound(1.0005, 3) // produces 1.001
precisionRound(1234.5, 0) // produces 1235
precisionRound(1234.5, -1) // produces 1230

九:

function precisionRoundMod(number, precision) {
  var factor = Math.pow(10, precision);
  var n = precision < 0 ? number : 0.01 / factor + number;
  return Math.round( n * factor) / factor;
}

This just adds a digit to the right when rounding decimals. MDN has updated the Math.round() page so maybe someone could provide a better solution.

你正在寻找一个<条码>印本/代码>,用于 Java,以便你能够以你所期望的格式,书写小差错的浮标(因为它们储存在双轨格式)。

Try javascript-sprintf,请:

var yourString = sprintf("%.2f", yourNumber);

页: 1

您也可使用Number.toFixed(,用于显示目的,如果你不单单单单单单单列入用于固定点的浮动点。

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

如果你想绕过这个小操作的问题,你可以使用<条码>。

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;

你必须思考一下你实际想要的多少位精干的数位数——他们可能 t,吃不上:

新的错误随着每一项进一步的行动而累积,如果你不提它,那么它就只会在增长。 产生结果的大型图书馆每步就简单地切断了最后2位数,数字共同处理器也有“正常”和“完全”的透镜。 提款对加工商来说是廉价的,但用文字(多面、分立和使用pov(......))来说非常昂贵。 良好的数学平衡将为你提供下限。

因此,至少你应当使全球的var/与 p(10,n)保持一致——这意味着你决定了你所需要的精准性...... 然后:

Math.floor(x*PREC_LIM)/PREC_LIM  // floor - you are cutting off, not rounding

你们也可以保持数学和最后的截断——假设你只是展示而不是结果。 如果你能够这样做,那么,“......”可能更有效率。

如果你做些什么,不想要砍掉,那么你也需要一个小的固定点,通常称为ep,这个小点比预期的最大错误高。 您的切除是最后两点 de子,然后是三点三点四点三点三点三点三点三点三点三点三点三点三点四舍五入。

Notice that for the general purpose use, this behavior is likely to be acceptable.
The problem arises when comparing those floating points values to determine an appropriate action.
With the advent of ES6, a new constant Number.EPSILON is defined to determine the acceptable error margin :
So instead of performing the comparison like this

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

资料来源:

你的洞察结果在以不同语言、加工商和操作系统实施浮动点方面是正确和相当一致的,唯一的变化是在浮标实际上是双重(或更高)的不准确度。

0.1 在双轨浮动点,如1/3(即0.3333333 333 ......)中,仅仅没有准确的处理方式。

如果您重新处理浮标always 期望出现小的四舍五入差错,因此,你总是不得不将所展示的结果四舍五入到可以察觉的地步。 反过来,由于所有计算方法都属于加工商的原居地,你获得非常快速和有力的算术。

解决办法大部分时间不是转向固定点算术,主要是因为其速度要慢得多,而只有99%的时间需要准确度。 如果你重新处理确实需要准确度(例如金融交易)的难题, Java稿或许是使用任何途径的最佳工具(因为你想强制实施固定点类型,静态语言可能更好)。

那么,我担心的是,这种解决办法是:浮动是迅速的,但却有小的四舍五入的错误——在显示其结果时,总是会四舍五入到一点。

0.6 * 3 it s awesome!)) For me this works fine:

function dec( num )
{
    var p = 100;
    return Math.round( num * p ) / p;
}

非常简单

工作(移除零线)

var num = 0.1*0.2;
alert(parseFloat(num.toFixed(10))); // shows 0.02

为了避免出现这种情况,你应采用惯用价值而不是浮动点。 因此,如果你想有2个立场的精确性,就会有100个,3个职位使用1 000个。 在展示时,你使用一种格式,以安装在分离器上。

许多系统不以这种方式工作。 因此,许多系统使用的是百分点(如惯性),而不是美元/欧元(浮动点)。

<><>Problem

Floating point can t store all decimal values exactly. So when using floating point formats there will always be rounding errors on the input values. The errors on the inputs of course results on errors on the output. In case of a discrete function or operator there can be big differences on the output around the point where the function or operator is discrete.

www.un.org/Depts/DGACM/index_spanish.htm 浮动点值投入和产出

So, when using floating point variables, you should always be aware of this. And whatever output you want from a calculation with floating points should always be formatted/conditioned before displaying with this in mind.
When only continuous functions and operators are used, rounding to the desired precision often will do (don t truncate). Standard formatting features used to convert floats to string will usually do this for you.
Because the rounding adds an error which can cause the total error to be more then half of the desired precision, the output should be corrected based on expected precision of inputs and desired precision of output. You should

  • Round inputs to the expected precision or make sure no values can be entered with higher precision.
  • Add a small value to the outputs before rounding/formatting them which is smaller than or equal to 1/4 of the desired precision and bigger than the maximum expected error caused by rounding errors on input and during calculation. If that is not possible the combination of the precision of the used data type isn t enough to deliver the desired output precision for your calculation.

这2件事通常没有做,在大多数情况下,由于不做这些改动而造成的差异太小,对大多数用户来说都很重要,但我已经有一个项目,即没有这些更正,用户就接受产出。

www.un.org/Depts/DGACM/index_spanish.htm 分散的职能或操作者(如模块)

When discrete operators or functions are involved, extra corrections might be required to make sure the output is as expected. Rounding and adding small corrections before rounding can t solve the problem.
A special check/correction on intermediate calculation results, immediately after applying the discrete function or operator might be required. For a specific case (modula operator), see my answer on question: Why does modulus operator return fractional number in javascript?

www.un.org/Depts/DGACM/index_spanish.htm 更好地避免出现问题

It is often more efficient to avoid these problems by using data types (integer or fixed point formats) for calculations like this which can store the expected input without rounding errors. An example of that is that you should never use floating point values for financial calculations.

Elegant, Predictable, and Reusable

让我们以可替代的方式处理这个问题。 下面七行将允许你通过在编号、公式或以<代码>Math功能上填入的<代码>,即可查阅你希望在任何编号上的浮动点精确度。

// First extend the native Number object to handle precision. This populates
// the functionality to all math operations.

Object.defineProperty(Number.prototype, "decimal", {
  get: function decimal() {
    Number.precision = "precision" in Number ? Number.precision : 3;
    var f = Math.pow(10, Number.precision);
    return Math.round( this * f ) / f;
  }
});


// Now lets see how it works by adjusting our global precision level and 
// checking our results.

console.log(" 1/3 + 1/3 + 1/3 = 1  Right?");
console.log((0.3333 + 0.3333 + 0.3333).decimal == 1); // true

console.log(0.3333.decimal); // 0.333 - A raw 4 digit decimal, trimmed to 3...

Number.precision = 3;
console.log("Precision: 3");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0.01
console.log((0.0008 + 0.0002).decimal); // 0.001

Number.precision = 2;
console.log("Precision: 2");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0.01
console.log((0.0008 + 0.0002).decimal); // 0

Number.precision = 1;
console.log("Precision: 1");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0
console.log((0.0008 + 0.0002).decimal); // 0

Number.precision = 0;
console.log("Precision: 0");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0
console.log((0.008 + 0.002).decimal); // 0
console.log((0.0008 + 0.0002).decimal); // 0

<><>Cheers!>

解决该问题的方法是,先对数字进行分类,执行表述,然后将结果分开,以重新定位:

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}`;
}

几个业务的结果(除外数字来自<代码>eval):

0.1 + 0.002   = 0.102 (0.10200000000000001)
53 + 1000     = 1053 (1053)
0.1 - 0.3     = -0.2 (-0.19999999999999998)
53 - -1000    = 1053 (1053)
0.3 * 0.0003  = 0.00009 (0.00008999999999999999)
100 * 25      = 2500 (2500)
0.9 / 0.03    = 30 (30.000000000000004)
100 / 50      = 2 (2)

从我的观点看,这里的想法是四舍五入,以便有一丝不.的表述。

The 53-bit significand precision gives from 15 to 17 significant decimal digits precision (2−53 ≈ 1.11 × 10−16). If a decimal string with at most 15 significant digits is converted to IEEE 754 double-precision representation, and then converted back to a decimal string with the same number of digits, the final result should match the original string. If an IEEE 754 double-precision number is converted to a decimal string with at least 17 significant digits, and then converted back to double-precision representation, the final result must match the original number.
...
With the 52 bits of the fraction (F) significand appearing in the memory format, the total precision is therefore 53 bits (approximately 16 decimal digits, 53 log10(2) ≈ 15.955). The bits are laid out as follows ... wikipedia

(0.1).toPrecision(100) ->
0.1000000000000000055511151231257827021181583404541015625000000000000000000000000000000000000000000000

(0.1+0.2).toPrecision(100) ->
0.3000000000000000444089209850062616169452667236328125000000000000000000000000000000000000000000000000

然后,根据我的理解,我们可以把最多15位数的数值四舍五入,以保持雄辩的代表性。

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;
}

查阅Fixed-point arithmetic。 如果你想要操作的人数很少(例如货币),这很可能解决你的问题。 我将把它同几个精干的价值观相去,这是最简单的解决办法。

您可以确切地代表双向浮动点类型(即欧空研中心为代表浮动点值而使用的文字)。 因此,除非你使用任意精确度的算术类型或基于精度的浮动点类型,否则就不会有一种迷惑的解决办法。 例如, 计算器认为,有Windows的船舶现在使用武断精确度算法解决这一问题。

你是正确的,其原因是浮动点数的精确度有限。 储存理性数字是两个分类的,在多数情况下,你能够储存数字而不会造成任何精确损失。 在印刷方面,你可能希望显示结果为零。 在我提议的情况下,它变得微不足道。

当然,赢得一定数目的无理帮助。 但是,你可能希望以引起最不问题的方式优化计算(例如,探测sqrt(3)^2>等情况)。

我有一个新生的四舍五入的错误问题,有三 mo。 有时,当我拿到零时,就会有000.01. 。 但有时我会收到2.9999999999999999998美元。 OUCH!

BigNumbers 解决了这一问题,但又提出了另一个具有讽刺意味的问题。 在试图将8.5装入大坝时,我被告知实际上为8.4999。 人数超过15名。 这意味着大都市不能接受(我认为我提到这个问题有些讽刺)。

铁质问题的简单解决:

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);

“entergraph

    You can use library https://github.com/MikeMcl/decimal.js/. 
    it will   help  lot to give proper solution. 
    javascript console output 95 *722228.630 /100 = 686117.1984999999
    decimal library implementation 
    var firstNumber = new Decimal(95);
    var secondNumber = new Decimal(722228.630);
    var thirdNumber = new Decimal(100);
    var partialOutput = firstNumber.times(secondNumber);
    console.log(partialOutput);
    var output = new Decimal(partialOutput).div(thirdNumber);
    alert(output.valueOf());
    console.log(output.valueOf())== 686117.1985

Avoid dealing with floating points during the operation using Integers

如在迄今表决最多的回答中所说,你可以与英寸合作,这将意味着把你的所有因素增加10倍,使你所工作的每一名男士都参与其中,并将结果与所使用的相同数目分开。

例如,如果你与2名男性工作人员合作,你在开展行动之前将全部因素增加100个,然后将结果划分为100个。

例如,结果1是通常的结果,结果2利用了解决办法:

var Factor1="1110.7";
var Factor2="2220.2";
var Result1=Number(Factor1)+Number(Factor2);
var Result2=((Number(Factor1)*100)+(Number(Factor2)*100))/100;
var Result3=(Number(parseFloat(Number(Factor1))+parseFloat(Number(Factor2))).toPrecision(2));
document.write("Result1: "+Result1+"<br>Result2: "+Result2+"<br>Result3: "+Result3);

第三个成果是显示在使用宗教基金时发生的情况,而后者在我们的案件中造成了冲突。

我无法利用<代码>建造的解决方案。 页: 1 ECSILON that s means to help with this summary, so here is my resolution:

function round(value, precision) {
  const power = Math.pow(10, precision)
  return Math.round((value*power)+(Number.EPSILON*power)) / power
}

采用已知最小的1点和最小的浮动点数之间的最低差异,以在四舍五入门槛值以下的圆差码

最大精确度为64bit15,浮动点和6,32bit浮动点。 你的手法很可能是64比方。

Try my chiliadic arithmetic library, which you can see here. If you want a later version, I can get you one.

第1.234443号

function test(){
    var x = 0.1 * 0.2;
    document.write(Number(x).toFixed(2));
}
test();




相关问题
热门标签