2

I have to do some calculations in JavaScript in client side and I have to validate in PHP when the user clicks on submit. When doing so I am getting different results in PHP and JavaScript.

I have the below problems.

1. JavaScript calculations gives extra numbers at the end after decimals.

2. JavaScript calculations and PHP calculations mismatch while validating in backend.

<script type="text/javascript">
var a = 130;
var b = 1.3595;
var c = a * b;
console.log(c);  //176.73499999999999
console.log(c.toFixed(2));  //176.73
</script>

<?php
$a = 130;
$b = 1.3595;
$c = $a * $b;
echo $c; //176.735
echo round($c,2); //176.74
?>

Both gives different result.So What I want is either 176.74 or 176.73 on both JavaScript and PHP.

svkks
  • 95
  • 2
  • 10
  • 2
    Possible duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Qirel May 10 '19 at 16:42
  • 1
    Javascript just cuts of decimal places, while php rounds the number, that's why it is one decimal point higher – Tudor May 10 '19 at 16:43
  • 1
    tell JS to round off , you will have the same answer –  May 10 '19 at 16:44
  • 1
    @Tudor Look at the first echo/print - the actual result of the math `130 * 1.3595` is different, it's not only that one cuts while the other rounds. That's because we're dealing with floating point math, which can sometimes be *slightly* incorrect. – Qirel May 10 '19 at 16:45
  • 1
    In PHP you're rounding and in JS you're truncating – j08691 May 10 '19 at 16:56
  • Can I Use like this Math.round(c * 100) / 100. For JS it gives 176.74.Can it be a correct solution? If not can you suggest some solution for this? – svkks May 10 '19 at 17:33
  • If you absolutely need a match 100 percent of the time...create an API call to PHP and pass your parameters and get a value back – Ctznkane525 May 10 '19 at 23:30

1 Answers1

0

To get the desired number of decimal precision, Math.round requires a multiplication followed by a division (the "multiply-and-divide" method).

This "multiply-and=divide" method can produce a roundoff error, but apparently it can be avoided by instead raising then lowering the number's exponent (call this the "exponent" method).

The "multiply-and-divide" method:

Math.round(num*100)/100

The "exponent" method:

Number(Math.round(num+'e2') + 'e-2')

Try the snippet below with num1 = 1.005, num2 = 1, decimals = 2. The "multiply-and-divide" method gets it wrong, the "exponent" method gets it right.

/* the "multiply-and-divide" rounding method */
function roundmult(value, decimals) {
  let multiplier = 1;
  for (let i = 0; i < decimals; i++) {
    multiplier *= 10;
  }
  return Math.round(value * multiplier) / multiplier;
}

/* the "exponent" rounding method */
function roundexp(value, decimals) {
  return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
}

function testIt() {
  let decimals = +(document.getElementById("decimals").value);
  let num1 = +(document.getElementById("num1").value);
  let num2 = +(document.getElementById("num2").value);

  let product = num1 * num2;
  let resultmult = roundmult(product, decimals);
  document.getElementById("multdiv").innerText = resultmult;
  let resultexp = roundexp(product, decimals);
  document.getElementById("exponent").innerText = resultexp;
}
<h1>
  Math.round() Test
</h1>
<label for="num1">num1</label>
<input id="num1" type="number"> times
<label for="num2">num2</label>
<input id="num2" type="number"><br />
<label for="decimals">decimal places:</label>
<input id="decimals" type="number"><br /><br />
<button id="doit" onclick="testIt();">
Round it!
</button><br /><br /> The "multiply and divde" method result is: <span id="multdiv"></span>
<br /><br /> The "exponent" method result is: <span id="exponent"></span>
terrymorse
  • 6,771
  • 1
  • 21
  • 27
  • I have checked. For some values it gives correct answer and for some it is not. Can you check with this value 40.785 . In PHP it's 40.79 and in JS it's 40.78 – svkks May 10 '19 at 20:03
  • @svkks - see my updated answer above. The snippet uses two different methods, please give them a try. – terrymorse May 10 '19 at 22:35