1
//value of currency denominations
    var currencyTable = [100, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01];

//total cash at each currencyTable denomination in the cash register 
    var cashInDrawer = [100, 60, 20, 55, 90, 4.25, 3.1, 2.05, 1.01];

//total change due
    var changeDue = 96.74;

My goal is to return the correct change from the cash available from the greatest cash denomination to the lowest.

I can't figure out how to increment a value in currencyTable up to the available amount in cashInDrawer while changeDue >= currencyTable[i].

I've managed so far:

var total = [];
  for (let i = 0; i < currencyTable.length; i++){
  while (changeDue >= currencyTable[i]){
    total.push(currencyTable[i])
    changeDue-=currencyTable[i];
  }
 }return total;

but this only returns:

[20, 20, 20, 20, 10, 5, 1, 0.25, 0.25, 0.1, 0.1, 0.01, 0.01, 0.01]

where I want to return:

[60, 20, 15, 1, 0.5, 0.2, 0.04]

Somewhere in the loop I realize changeDue is being changed into a repeating decimal but I found a temporary workaround using .toFixed().

Sam Harris
  • 11
  • 3
  • Don't push `currencyTable[i]` on every round of the `while` loop. Instead sum the values up and only push the sum after the `while` loop. – Andreas Dec 08 '18 at 09:08

2 Answers2

2

You're completely on the right path. But instead of calling push each time in the inner loop, you need to add to the amount you pushed the previous time when you're looping. Probably the easiest way to do that is to have a variable you add to, and then push at the end. You also have to check against cashInDrawer and reduce cashInDrawer when you add to `total.

There is a problem inherent in this: You're using JavaScript's number type to deal with money. But JavaScript's number type isn't suited to dealing with money, IEEE-754 binary floating point values have notorious imprecision issues in the decimal realm, such as the famous:

console.log(0.1 + 0.2); // 0.30000000000000004

And that comes up in this problem. If we just apply the logical fixes above, we get (see *** lines):

//value of currency denominations
var currencyTable = [100, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01];

//total cash at each currencyTable denomination in the cash register 
var cashInDrawer = [100, 60, 20, 55, 90, 4.25, 3.1, 2.05, 1.01];

//total change due
var changeDue = 96.74;

var total = [];
for (let i = 0; i < currencyTable.length; i++){
    let amount = 0;                                                 // ***
    while (changeDue >= currencyTable[i] && cashInDrawer[i] > 0) {  // ***
        amount += currencyTable[i];                                 // ***
        changeDue -= currencyTable[i];
        cashInDrawer[i] -= currencyTable[i];                        // ***
    }
    // I assume you want to push the amount even if it's 0
    total.push(amount);                                             // ***
}
//return total;
console.log(total);

Notice that the last entry is 0.03, not 0.04. That's because changeDue is getting more and more imprecise as we go, which we can see if we log it:

//value of currency denominations
var currencyTable = [100, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01];

//total cash at each currencyTable denomination in the cash register 
var cashInDrawer = [100, 60, 20, 55, 90, 4.25, 3.1, 2.05, 1.01];

//total change due
var changeDue = 96.74;

var total = [];
for (let i = 0; i < currencyTable.length; i++){
    let amount = 0;                                                 // ***
    while (changeDue >= currencyTable[i] && cashInDrawer[i] > 0) {  // ***
        amount += currencyTable[i];                                 // ***
        changeDue -= currencyTable[i];
        cashInDrawer[i] -= currencyTable[i];                        // ***
        console.log(changeDue);
    }
    // I assume you want to push the amount even if it's 0
    total.push(amount);                                             // ***
}
//return total;
console.log(total);

At the end, 0.009999999999994869 is not >= 0.1 and so the loop ends early.

See this question's answers for various approaches to fixing that.

One common solution is to use the numbers * 100 and keep rounding. (Sometimes you might use * 10000 and then round back to two decimal places, etc.) Here's the general idea, tweak as necessary:

//value of currency denominations
var currencyTable = [100, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01];
currencyTable = currencyTable.map(entry => Math.round(entry * 100));   // ***

//total cash at each currencyTable denomination in the cash register 
var cashInDrawer = [100, 60, 20, 55, 90, 4.25, 3.1, 2.05, 1.01];
cashInDrawer = cashInDrawer.map(entry => Math.round(entry * 100));     // ***

//total change due
var changeDue = 96.74;

changeDue = Math.round(changeDue * 100);                                // ***
var total = [];
for (let i = 0; i < currencyTable.length; i++){
    let amount = 0;
    while (changeDue >= currencyTable[i] && cashInDrawer[i] > 0) {
        amount += currencyTable[i];
        changeDue -= currencyTable[i];
        cashInDrawer[i] -= currencyTable[i];
    }
    // I assume you want to push the amount even if it's 0
    total.push(amount);
}
//return total;
for (const entry of total) {
    console.log(entry / 100);
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    Thank you so much. At one point when I was working on this I had the idea that I'd need another placeholder variable to push values of currencyTable[i] before pushing to the total onto the total array but for whatever reason I never did. – Sam Harris Dec 11 '18 at 14:48
-1

You need to aggregate the number of items of currency. Try following

var total = [];
    for (let i = 0; i < currencyTable.length; i++){
        var cCount = 0;
        while (changeDue >= currencyTable[i]){
            cCount++;
            changeDue-=currencyTable[i];
        }
        total.push(cCount*currencyTable[i])
    }
    return total;
  • This is okay as far as it goes, but still leads to the wrong result for multiple reasons (it doesn't handle `cashInDrawer`, doesn't handle floating point imprecision, ...) – T.J. Crowder Dec 08 '18 at 09:27