11

I'm trying to round a float number in Javascript in the same way that I do it in PHP; but I can not make both languages ​​round in the same way the following number:6.404999999999999

When I use PHP round I get: 6.41, but when I trying to round with Javascript I always get 6.40

INFO: The correct answer is https://stackoverflow.com/a/54721202/4359029

My Javascript attempts:

Attempt #1:

module.exports = function round (value, precision, mode) {
  var m, f, isHalf, sgn // helper variables
  // making sure precision is integer
  precision |= 0
  m = Math.pow(10, precision)
  value *= m
  // sign of the number
  sgn = (value > 0) | -(value < 0)
  isHalf = value % 1 === 0.5 * sgn
  f = Math.floor(value)

  if (isHalf) {
    switch (mode) {
      case 'PHP_ROUND_HALF_DOWN':
      // rounds .5 toward zero
        value = f + (sgn < 0)
        break
      case 'PHP_ROUND_HALF_EVEN':
      // rouds .5 towards the next even integer
        value = f + (f % 2 * sgn)
        break
      case 'PHP_ROUND_HALF_ODD':
      // rounds .5 towards the next odd integer
        value = f + !(f % 2)
        break
      default:
      // rounds .5 away from zero
        value = f + (sgn > 0)
    }
  }

  return (isHalf ? value : Math.round(value)) / m
}

Extracted from: http://locutus.io/php/math/round/

Attempt #2:

round(decimal: number, decimalPoints: number): number{
    let roundedValue = Math.round(decimal * Math.pow(10, decimalPoints)) / Math.pow(10, decimalPoints);

    console.log(`Rounded ${decimal} to ${roundedValue}`);
    return roundedValue;
}

Extracted from: https://stackoverflow.com/a/50918962/4359029


I tried with other solutions... but without success.

Could someone tell me how to get the rounding of Javascript to act like PHP's?

Could you tell me why they work in different ways in the case I explain?

tomloprod
  • 7,472
  • 6
  • 48
  • 66
  • 1
    This might be because PHP does have an accurate binary representation of the number and knows that the number is actually `6.405` but is unable to display it accurately in decimal. [this is a good read about this](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) the problem is that in all likelyhood when you send the decimal representation of that number to JavaScript the accurate binary representation is lost and JavaScript has to work with noisy data. I doubt there is anything to do other than send the ops to JavaScript and have it do the calculation from scratch – apokryfos Nov 23 '18 at 16:59

4 Answers4

4

I think the best answer is the next:

function roundLikePHP(num, dec){
  var num_sign = num >= 0 ? 1 : -1;
  return parseFloat((Math.round((num * Math.pow(10, dec)) + (num_sign * 0.0001)) / Math.pow(10, dec)).toFixed(dec));
}

I tried the other solutions with 1.015 and doesn't work as expected.

This solution works well, like PHP round, with all the numbers I tried.

tomloprod
  • 7,472
  • 6
  • 48
  • 66
  • 1
    Best answer! :) Thanks @tomloprod – Sajjad Ali Nov 19 '20 at 07:06
  • While this function is close to the php function it still returns different results in some cases. for example roundLikePHP(0.49999,0) = 1 while in php round(0.49999) = 0 . – Andyba Dec 09 '20 at 11:47
  • @Andyba Hi. This problem only occurs when rounding to 0 decimal places, so at least in my case, it doesn't affect me – tomloprod Dec 09 '20 at 11:50
  • @tomloprod Not quite: roundLikePHP(0.004999999,2) = 0.01 and in php round(0.004999999,2) = 0 – Andyba Dec 09 '20 at 14:10
3

You can use toPrecision Function

It will rounded by the precision provided. Here I rounded by 4 to get 6.405 and then rounded by 3 to get 6.41

parseFloat((6.404999999999999).toPrecision(4)).toPrecision(3);

console.log(parseFloat((6.404999999999999).toPrecision(4)).toPrecision(3));
Niklesh Raut
  • 34,013
  • 16
  • 75
  • 109
  • 1
    Could you explain why your solution doesn't work with the next number: `1.015`? This rounds to `1.01` instead of `1.02` – tomloprod Feb 15 '19 at 18:09
2

You could do it like this:

function roundToXDigits(value, digits)
{
    if (!digits) {
        digits = 2;
    }

    value = value * Math.pow(10, digits);
    value = Math.round(value);
    value = value / Math.pow(10, digits);

    return value
}

var num = roundToXDigits(6.404999999999999, 3); //creates 6.405

console.log(roundToXDigits(num, 2)); //creates 6.41

The problem is, JavaScript technically isn't wrong. 6.4049 -> becomes 6.405 when you round (which, to 2dp is 6.40) which is why it's not working as expected. You have to run the function twice to round 405 -> 41.

Source: JavaScript math, round to two decimal places

^^ extension usage of Bryce's answer.

treyBake
  • 6,440
  • 6
  • 26
  • 57
  • @tomloprod no prob, hope it helps :) – treyBake Nov 23 '18 at 16:54
  • treyBake Works well! I think it's similar to @C2486 answer. Guys, what solution do you think is the best? – tomloprod Nov 23 '18 at 17:08
  • @tomloprod : Its always good to explore any method deeply, but the best practice is to use inbuilt method provided by any language or framework. Its good to see detail code of `toPrecision` as `roundToXDigits`.this `roundToXDigits` method would be great if the inbuilt method is not supported by any version of browser. – Niklesh Raut Nov 23 '18 at 17:13
  • 1
    @treyBake Could you explain why your solution doesn't work with the next number: `1.015`? This rounds to `1.01` instead of `1.02` – tomloprod Feb 15 '19 at 18:09
  • @tomloprod hmm not 100% sure, can you maybe paste a jsfidddle of usage of function? :) – treyBake Feb 18 '19 at 10:28
  • @treyBake In this JSFiddle you can show how your function doesn't work as PHP with the next number: "1.015": https://jsfiddle.net/u3jefrph/ Anyway, if you see my own answer (https://stackoverflow.com/a/54721202/4359029) , you will find the solution that I have finally implemented to solve this problem – tomloprod Feb 19 '19 at 08:24
  • 1
    @tomloprod this solution is not working with 1.015 because in JS 1.015*100=101.49999999999999 – Andyba Dec 09 '20 at 10:39
1

You might try

console.log(Number(n.toFixed(3)).toFixed(2));

eg.

var n = 6.404999999999999;
console.log(n.toFixed(2)); //=> 6.40
console.log(n.toFixed(3)); //=> 6.405
Chameera
  • 82
  • 8
  • @RokoC.Buljan, There is a fundamental difference between the round method in PHP and javascript. But according the basic definition of the round functionality, the values are equal to results of JavaScript. – Chameera Nov 23 '18 at 17:14
  • How about this, `console.log(Number(n.toFixed(3)).toFixed(2));` – Chameera Nov 23 '18 at 17:19