Cash Register - off by one penny

After much blood, sweat, and tears I have gotten the cash register functional.

It is passing all but the third test. In this case it is stopping one penny too soon. Currently in the codepen I have it logging the output of the makeChange() function to the console so you can see the array.

Can someone help me understand why this is happening?

I’m going to chug some more coffee and come back to this later :sweat_smile:

https://codepen.io/clairesouthwell/pen/eaLYyp?editors=1112

2 Likes

I noticed the status was insufficient funds when logging (3.26, 100,…
Your code is failing only 2 tests so we’re close! :vulcan_salute:

1 Like

I actually found the bug that was causing the change to be doubled. Now it is passing all tests except the one you mentioned, where the cost is $3.26.

I checked what my makeChange() function is outputting and it is stopping one penny too soon. (This is currently included in the codepen.)

Can you help me understand why this is happening?

Thanks for taking a look!

1 Like

Something doesn’t look right to me here

for (let i = slots.length - 1; i > -1; )

Just checked on the forum and found other’s loops looking this way:

for(let i=0; i<currency.length; i++)
 

:vulcan_salute:

I would suggest reversing your ‘slots’ array so it’s in the same order as the cash-in-drawer (cid) and input ‘arr’. This not only saves syncing a your ascending order ard descending order arrays, it also lets you use the same index in your loop (eg if (slots[i] == cid[i][1]) { doStuff; }.

Scott’s point about the decrementing loop shouldn’t be causing the issue, though normally syntax would be closer to for (let i = slots.length - 1; i >= 0; i--) and in the body of the loop, you’d break; instead of manually decrementing (else { i--; })

It would also help you to console.log() the content of the returned cash drawer - it makes it easier to work out where the error is occurring, and gives experience in dealing with arrays of objects.

hth

1 Like

I put the decrement in the function because I only wanted it to happen under certain conditions. Since the decrement essentially means “move on to the next currency unit”, we don’t necessarily want to do that on every iteration of the loop. If the change owed is $45, I want to give 2 $20’s, not $20 and then decrement (to give $10).

All that said, it seems to be working exactly the way I want it to except that in the case where 4 pennies are owed, the loop is terminating too early, while $0.01 is still owed, so it returns the value false.
I did console.log() the returned cash drawer in that case, which is how I realized that it was stopping just $0.01 too soon. That test is included in the codepen.

Does that make sense? I am really happy with the overall structure of the makeChange() function and am really hoping that I can fix this bug without having to rip it apart too much.

1 Like

I actually did it that way for a reason - see reply below. If you have any idea why it is doing all the iterations correctly but then stopping one iteration too soon, that would be really helpful.

1 Like

I needed some coffee too! Here’s some code that may be of benefit to you!! Reverse engineering syntax is very challenging yet so much fun!!! :vulcan_salute:

1 Like

I’m pretty sure it’s a rounding error, but I can’t work out where. Run:

console.log(makeChange([["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]], 96.71));
console.log(makeChange([["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]], 96.72));
console.log(makeChange([["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]], 96.73));
console.log(makeChange([["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]], 96.74));

and watch the change errr, change. :slight_smile:

For my version, I used something like:
money = money.toFixed(2);
where (I’m guessing) you use:
money = Math.floor(money * 100) / 100;
but when I tried to plug ‘toFixed()’ in your code, it made no difference, so I figure it must be during another arithmetic function.

2 Likes

Thank you for the response! I already had encountered a rounding error when using a function to add up the cid array into the drawerBalance variable, so it makes sense that there was one occurring here as well.
Unfortunately, when I I tried using these methods, my code actually started failing the final test, which it previously passed, as well as the 3rd one. :frowning:

Thank you… I tried implementing rounding to make the variables more accurate in my own code, but now it is also failing the 6th test as well as the 3rd one. :frowning:

OK, in your code now, if you change money = Math.floor(money * 100) / 100; to money = money.toFixed(2);, test 6 passes.

Now, this is weird. Add:

console.log("change due: " + changeDue + ", drawerBalance: " + drawerBalance + ": cd > db? " + (changeDue > drawerBalance));
just before
if (changeDue > drawerBalance) {
and have a look at the output for test 3 (???)

:rofl: Why is it saying that?!?

I’m perplexed. My only guess was that the ‘number’ type was only for (really) low numbers (eg int32 vs int64 in c#), but it seems javascript only has one numeric type and it is stored as a double precision floating point number which is accurate up to 15 digits so that’s not it. (And 335.41 is stupidly low even if javascript had different numeric types.)

It might be worth asking a question about this specific phenomena in the forum so new eyes have a look.

  1. I’d suggest wrapping your toFixed calls in Number() so you are not using strings.

  2. The algorithm is working it is just the way you use the makeChange function. Try calling and capturing the return one time and use it for the if statement and return value.

if (changeDue < drawerBalance) {
  let changeBack = makeChange(cid, changeDue);
  if (changeBack == false) {
    return { status: 'INSUFFICIENT_FUNDS', change: [] };
  } else {
    return { status: 'OPEN', change: changeBack };
  }
}
1 Like

Ah yes… I learned that about toFixed() earlier today and facepalmed so hard. I’ll give this a shot later tonight. Thank you for the help!