2

I am creating a simple calculator to show the fewest number of coins necessary to make an amount of change. The user inputs the change amount, and the function outputs the number of quarters, dimes, nickles, and pennies necessary. The code appears to function perfectly unless the hundreds digit (the pennies digit) is a 3 or an 8. In that case, it outputs one less penny than is needed. Is this improper output caused by the use of Math.ceil or toFixed in this context? What could be used instead?

I was having problems with the window displaying non-whole numbers of coins as a solution, which is why I began using Math.ceil() and toFixed().

function changeCalc() {
  let a = document.getElementById("changeTotal").value;
  let b = (a % 0.25).toFixed(2);
  let quartersNum = Math.ceil((a - b) / 0.25);
  if (b > 0) {
    var c = (b % 0.1).toFixed(2);
    var dimesNum = Math.ceil((b - c) / 0.1);
    if (c > 0) {
      var d = (c % 0.05).toFixed(2);
      var nicklesNum = Math.ceil((c - d) / 0.05);
      if (d > 0) {
        var e = (d % 0.01).toFixed(2);
        var penniesNum = Math.ceil((d - e) / 0.01);
        document.getElementById("changeWindow").innerHTML =
          `${quartersNum} quarters, ${dimesNum} dimes, ${nicklesNum} nickles, 
            ${penniesNum} pennies`;
      } else {
        document.getElementById("changeWindow").innerHTML =
          `${quartersNum} quarters, ${dimesNum} dimes, ${nicklesNum} 
               nickles`;
      }
    } else {
      document.getElementById("changeWindow").innerHTML =
        `${quartersNum} quarters, ${dimesNum} dimes`;
    }
  } else {
    document.getElementById("changeWindow").innerHTML =
      `${quartersNum} quarters`;
  }
}

For example, when I enter .18 as the change value, I expect the output to be 0 quarters, 1 dimes, 1 nickles, and 3 pennies. Instead, the output is 0 quarters, 1 dimes, 1 nickles, and 2 pennies.

AVAVT
  • 7,058
  • 2
  • 21
  • 44

2 Answers2

0

Yes indeed it does.

In your case: everytime d=0.03, e is going to be 0.01, because (0.03 % 0.01) will be calculated to 0.009999999999999998 which will evaluated t0 0.01 by .toFixed(2).

But for your problem, this could be solved if u change

if (d > 0) {
   var e = (d % 0.01).toFixed(2);
   var penniesNum = Math.ceil((d - e) / 0.01);

to

if (d > 0) {
   var penniesNum = Math.ceil((d) / 0.01);

I hope this helps you somehow.

0

This is not really a problem with toFixed() or ceil() but more precisely a Floating-Point Imprecision issue, especially with javascript.

There are many ways to resolve it, but for your problem, it is commonly resolved by using a solution that doesn't have to deal with floating point numbers e.g. multiply the initial numbers by 100 to get 18, then you would have avoided the issue entirely.

function changeCalc(inputString) {
  let a = parseInt(inputString * 100);
  let b = a % 25;
  let quartersNum = Math.floor(a / 25);
  if (b > 0) {
    var c = b % 10;
    var dimesNum = Math.floor(b / 10);
    if (c > 0) {
      var d = c % 5;
      var nicklesNum = Math.floor(c / 5);
      if (d > 0) {
        var penniesNum = d;
        console.log(
          `${quartersNum} quarters, ${dimesNum} dimes, ${nicklesNum} nickles, 
        ${penniesNum} pennies`);
      } else {
        console.log(
          `${quartersNum} quarters, ${dimesNum} dimes, ${nicklesNum} 
           nickles`);
      }
    } else {
      console.log(
        `${quartersNum} quarters, ${dimesNum} dimes`);
    }
  } else {
    console.log(
      `${quartersNum} quarters`);
  }
}

console.log("$0.18 is:");
changeCalc("0.18");

console.log("$0.24 is:");
changeCalc("0.24");

console.log("$0.33 is:");
changeCalc("0.33");
AVAVT
  • 7,058
  • 2
  • 21
  • 44