1

I'm trying to make a function that takes an amount of cash, and deducts the amount of coins/bills needed to make up that amount of cash from existing variables. The code I have looks like this:

var changeDue = 34.66;

  // get number of each coin
  var penny   = 50;
  var nickel  = 50;
  var dime    = 50;
  var quarter = 50;
  var one     = 50;
  var five    = 50;
  var ten     = 50;
  var twenty  = 50;
  var hundred = 50;

  function getChange(due) {
    var currentDue = due;
    while(currentDue > 0) {
      if(currentDue >= 100 && hundred > 0){
        hundred--;
        currentDue -= 100;
      }
      else if(currentDue >= 20 && twenty > 0) {
        twenty--;
        currentDue -= 20;
      }
      else if(currentDue >= 10 && ten > 0) {
        ten--;
        currentDue -= 10;
      }
      else if(currentDue >= 5 && five > 0) {
        five--;
        currentDue -= 5;
      }
      else if(currentDue >= 1 && one > 0) {
        one--;
        currentDue -= 1;
      }
      else if(currentDue >= 0.25 && quarter > 0) {
        quarter--;
        currentDue -= 0.25;
      }
      else if(currentDue >= 0.1 && dime > 0) {
        dime--;
        currentDue -= 0.1;
      }
      else if(currentDue >= 0.05 && nickel > 0) {
        nickel--;
        currentDue -= 0.05;
      }
      else if(currentDue >= 0.01 && penny > 0) {
        penny--;
        currentDue -= 0.01;
      }
    }
    console.log(currentDue);
  }

  getChange(changeDue);

What I'm trying to do with the while loop is to check if the amount of change due is above a certain bill/coin like one hundred and there are still coins or bills of this value available, and then deduct from the change due and amount of coins/bills. But this is resulting in an infinite loop, so I can't debug it.

I thought that since I am always deducting from currentDue and I have set such a high number of coins and bills I wouldn't have such a problem but I do. Can someone point out what I am doing wrong?

Thank you

mlamp
  • 773
  • 2
  • 9
  • 21
  • 2
    An infinite loop doesn't mean you can't debug it. Put the console.log inside the loop with `debugger;` and the browser will pause at each iteration. – JJJ Feb 13 '16 at 01:06
  • Your issue has to due with the floating point precision of javascript. See http://stackoverflow.com/questions/1458633/how-to-deal-with-floating-point-number-precision-in-javascript – Craig Swing Feb 13 '16 at 01:08
  • 4
    One potential problem is that you have no `else` condition, so if none of your conditions are met => infinite loop – Rob M. Feb 13 '16 at 01:08
  • @CraigSwing `0.011` would cause infinite loop even if there would be no floating point imperfections – Alexei Levenkov Feb 13 '16 at 01:10
  • 2
    When dealing with money, the best recommendation is to do everything with integers in units of cents, rather than fractions of dollars. Then you don't have to deal with floating point problems. – Barmar Feb 13 '16 at 01:17

3 Answers3

2

The first operation is 34.66 - 20, in JavaScript 34.66 - 20 = 14.659999999999997 (maybe you can round the result).

So, the currentDue will be 0.009999 for example, so, you never exit for that loop.

ferc
  • 41
  • 5
2

There are two reasons why your loop might be infinite:

  1. The imprecision of floating point numbers, which JavaScript and other languages use to represent numbers with decimal places
  2. The fact that there is no way to exit the loop if you run out of coins

In this example, the first is the reason, but you should address both.

To address the first problem, you can do one of two things. You can multiply everything by 100 to use integers instead, and then divide by 100 at the end to get the answer, like so:

if(currentDue >= 10000 && hundred > 0){
  hundred--;
  currentDue -= 10000;
}

...

console.log(currentDue / 100);

Or you could use Math.round(), like so:

if(currentDue >= 100 && hundred > 0){
  hundred -= 1;
  currentDue = Math.round(currentDue - 100);
 }

The first of these solutions will be more performant if that matters at all. Otherwise, take your pick.

To address the second problem, you can add a break statement if none of the above conditions are true:

...

else {
  break;
}
McMath
  • 6,862
  • 2
  • 28
  • 33
  • Thank you for the detailed explanation! Working with integers instead solved my problem. – mlamp Feb 13 '16 at 01:39
-1

It loops due to floating point issues, but it would loop also for large values of due,in particular for values over 6820.5 (that is, 50x100 + ... +50x0.01). Since hundred is 50 initially, the if condition

   if(currentDue >= 100 && hundred > 0){
    hundred--;
    currentDue -= 100;
  }

will be repeated until and hundred=0, that is, 50 loops. After that currentDue = due -5000 hundred=0...and the following if applies.

If due is over 6800 at this moment currentDue is over 1800.

Repeat the process and you will find due > 0 and hundred, ... equal to 0.

At this point no if condition applies, and since there is no else, the program loops

RafaelCaballero
  • 1,555
  • 2
  • 17
  • 24