简体   繁体   中英

Floating point issue. JavaScript

Basically my question is: Why do I get value as 130.00000000000003 instead of 130.0 ?

I just outputted everything that goes under the hood and hope it's clear enough. I know it's most likely the string/float is what causing this but i am not sure how to solve it.

I have tried parseFloat() , parseFloat().toFixed(1) , parseFloat().round(1) but still I keep getting that .00000000000003. Not always, but sometimes.

Code :

// ... 'cost' will be passed as a parameter to the function 

 totalBudget = parseFloat(document.getElementById('currentBudget').value);// e.g value ='4' 

 ni = parseFloat(totalBudget);
 cost = (cost).toFixed(1);
 alert("totalBudget " + totalBudget + "\nni " + ni + "\ncost " + cost);
 ni += parseFloat(cost);
 alert("ni " + ni);

 alert('\nni= ' + ni + '\ntotalBudget= ' + totalBudget + '\ncost=' + cost);

 var playerCost = parseFloat(document.getElementById('playerCost' + vTemp).value);
 playerCost = (playerCost).toFixed(1);
 alert('playerCost= ' + playerCost);
 alert('\nNow will subtract ');
 ni -= playerCost;
 alert('\nAfter Subtraction');
 alert('\nni= ' + ni + '\nplayerCost= ' + playerCost);


alert('-------'+
'\ncurrBudget= '+totalBudget+
'\nnew budget ni= '+ni+
'\nPlayer#:vTemp= '+vTemp+
'\nCurr player cost= '+playerCost+
'\nNew players cost= '+cost +
"\nParseFloat(playerCost)for curr player= "+parseFloat(playerCost));

Output:

 // If cost = 7.2 and playerCost= 7.1. Notice all floating values are super fine. 
    totalBudget 129.8
    ni 129.8
    cost 7.2

    totalBudget 129.8
    ni 129.8
    cost 7.2


    ni= 137
    totalBudget= 129.8
    cost=7.2

    plaerCost= 7.1

    Now will subtract 
    After Subtraction


    ni= 129.9
    playerCost= 7.1


    -------
    currBudget= 129.8
    new budget ni= 129.9
    Player#:vTemp= 8
    Curr player cost= 7.1
    New players cost= 7.2
    ParseFloat(playerCost)for curr player= 7.1

Without refreshing the page, I do some other operation on the website

Output:

// If cost = 7.3 and playerCost= 7.2. Notice floating points are totally not fine. 
totalBudget 129.9
ni 129.9
cost 7.3

ni 137.20000000000002

ni= 137.20000000000002
totalBudget= 129.9
cost=7.3

plaerCost= 7.2

Now will subtract 

After Subtraction

ni= 130.00000000000003
playerCost= 7.2

-------
currBudget= 129.9
new budget ni= 130.00000000000003
Player#:vTemp= 8
Curr player cost= 7.2
New players cost= 7.3
ParseFloat(playerCost)for curr player= 7.2

Then I will get "Over budget. Please change your players!" error cause 130.00000000000003 > 130.0

Attempts to do "money math" with (binary) floating point in any programming language are doomed to such a fate. Floating point involves binary fractions, not decimal fractions, and so there will be such anomalies introduced inevitably.

Note that toFixed() converts a floating point number to a string. It doesn't really help much.

edit — a comment correctly points out that floating point formats are not necessarily binary floating point formats. I think old IBM mainframes (maybe current z-series machines for all I know) used a base-16 exponent and (maybe) base-16 mantissas. Nowadays, however, IEEE-754 format is (for good or ill) pretty universal, and it's the format used by x86 machines. GPUs aren't (necessarily; I think the 32-bit NVidia floating point is pretty close) all IEEE-754 but all the ones I know of are binary floating point systems. (And, specifically, JavaScript is binary floating point by definition of the language.)

edit again — Eric Postpischil schools me in the comments below :-)

Maybe an overkill for this, but try BigDecimal . Floating points are not good for precision math, and javascript has no built in "decimal" type to handle it.

Also if precision is not that big of an issue, try the toPrecision() method. It will just cut off the parts you don't need.

var a = 1.000000000000005;
var b = a.toPrecision(6); //returns a string
var c = parseFloat(b); //returns a number
alert(b); // shows 1.000000;
alert(c); // shows 1;

EDIT: Actually you should be fine with

function roundFloat(input, prec) {
    return parseFloat(input.toFixed(prec));
}

and use it on the numbers in need of rounding.

If you have one significant decimal place, multiply with 10, truncate to integer and compare that:

var budget = 130.00000000000003;
var c1 = Math.round(budget * 10);
var c2 = Math.round(130 * 10);

if (c1 > c2)
    do_something;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM