6

I am having some problems with the way PHP and javascript round numbers. I am using PHP's round function and this javascript function:

function roundNumber(number, decimals) {     
    var newnumber = new Number(number+'').toFixed(parseInt(decimals));
    var value = parseFloat(newnumber);
    return value;
}

The number i am trying to round is 43.65 * 2.5 + 40% which when done using a calculator = 152.775 or when rounded in PHP = 152.78.

In javascript when i do a console.log the number is 152.774999999998 and when rounded with the above function gives me 152.77

Any help to reslove this issue is greatly appreciated

user3335966
  • 2,673
  • 4
  • 30
  • 33
Pjn2020
  • 527
  • 1
  • 8
  • 18
  • 1
    This is why we do not use floating-point numbers for currency. – Ignacio Vazquez-Abrams Jun 22 '11 at 08:37
  • http://stackoverflow.com/questions/5490687/broken-tofixed-implementation – mplungjan Jun 22 '11 at 08:39
  • Make sure when you use `parseInt` that you specify a radix; usually you want to work in base 10, so: `parseInt(yourNumber,10)`. – nnnnnn Jun 22 '11 at 08:46
  • 1
    Can someone explain to me why in PHP round(22.044960000000003,2) becomes 22.04 And round( 152.77499999999998,2) becomes 152.78 Why is the second one rounding up to 152.78 when i only want 2 dp's – Pjn2020 Jun 22 '11 at 12:33

6 Answers6

5

This isn't anything to do with rounding per se, but is to do with how decimal numbers are represented in binary-based hardware.

Check out the floating point guide for lots more information on this, as well as solutions/alternatives.

Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
4

Please have a look at How to deal with floating point number precision in JavaScript?

Here is an example

function roundNumber(number, decimals) {
  decimals = parseInt(decimals,10);
  var dec = Math.pow(10,decimals)
  console.log(dec,parseFloat(number)*dec);
  number=""+Math.round(parseFloat(number)*dec+.0000000000001); // fixed the .X99999999999
  return parseFloat(number.slice(0,-1*decimals) + "." + number.slice(-1*decimals))     
}


var val = 43.65 * 2.5;
    val+= val*0.40

console.log(val+' ~= 152.78? --> '+roundNumber(val,2).toFixed(2));
console.log('15.803 ~= 15.80? --> '+roundNumber(15.803,2).toFixed(2));
console.log('15.805 ~= 15.81? --> '+roundNumber(15.805,2).toFixed(2));
console.log('14.803 ~= 14.80? --> '+roundNumber(14.803,2).toFixed(2));
console.log('0.575 ~=  0.58? --> '+roundNumber(0.575,2).toFixed(2));
Community
  • 1
  • 1
mplungjan
  • 169,008
  • 28
  • 173
  • 236
3

I was thinking a bit on this, and wanted to share my solution, let it not go to waste:

function roundNumber(number, decimals) {      
    var d = parseInt(decimals,10),
        dx = Math.pow(10,d),
        n = parseFloat(number),
        f = Math.round(Math.round(n * dx * 10) / 10) / dx;
    return f.toFixed(d);
}

This does not use string functions, or any forced up or down rounding.

Test it here: http://jsfiddle.net/inti/hMrsp/4/

Edit: corrected, was cutting down zeros at the end

aorcsik
  • 15,271
  • 5
  • 39
  • 49
1

php rounds to 152.78, because it sees 152.77499 which is 152.775 and in the end 152.178. can't you use rounded value from php?

Dimitar Marinov
  • 922
  • 6
  • 14
1

It is because the different precisions used in JS (by the browser) and PHP or actually how many bits are used to store the numbers.

you can make your JS rounding function do this to round to the 2nd digit Math.round(floatNumber*100)/100

venimus
  • 5,907
  • 2
  • 28
  • 38
-1

Find below javascript function for number format

<script type="text/javascript">
function format_number(pnumber,decimals){
    if (isNaN(pnumber)) { return 0};
    if (pnumber=='') { return 0};

    var snum = new String(pnumber);
    var sec = snum.split('.');
    var whole = parseFloat(sec[0]);
    var result = '';

    if(sec.length > 1){
        var dec = new String(sec[1]);
        dec = String(parseFloat(sec[1])/Math.pow(10,(dec.length - decimals)));
        dec = String(whole + Math.round(parseFloat(dec))/Math.pow(10,decimals));
        var dot = dec.indexOf('.');
        if(dot == -1){
            dec += '.';
            dot = dec.indexOf('.');
        }
        while(dec.length <= dot + decimals) { dec += '0'; }
        result = dec;
    } else{
        var dot;
        var dec = new String(whole);
        dec += '.';
        dot = dec.indexOf('.');
        while(dec.length <= dot + decimals) { dec += '0'; }
        result = dec;
    }   
    return result;
}

var value = format_number(newnumber,2);
</script>
Sanjeev Chauhan
  • 3,977
  • 3
  • 24
  • 30
  • 1
    That seems a bit excessive - and I find it poor form not to credit where you got it from. http://www.codingforums.com/archive/index.php/t-190997.html – mplungjan Jun 22 '11 at 08:54