Reputation: 21
So I wrote this small practice program that tells you how many nickels and cents you would need for the amount given. I don't undersand why the program outputs 0 for cents even the the math is correct. I can't seam to understand what the issue is.
// Example program
#include <iostream>
using namespace std;
int main()
{
const double nickels{0.05};
const double cents{0.01};
int amt_needed_nickels{0}, amt_needed_cents{0};
double amt_val{0.06f}; // for 0.06 cents
double amt_val_copy{amt_val};
amt_needed_nickels = amt_val / nickels;
if(amt_needed_nickels != 0)
amt_val -= (nickels * amt_needed_nickels);
amt_needed_cents = amt_val / cents;
cout << "If it costs $" << amt_val_copy << ", you'll need:\nNickels: " << amt_needed_nickels << "\nCents: " << amt_needed_cents << "\n";
cout << "Even though amt_val is " << amt_val << ", and cents is also " << cents << ", and 0.01/0.01 does equal 1, why is amt_needed_cents not 1?\n";
}
To be fair I know if i change the const double cents{0.01} to const float cents{0.01}, and remove the f from double amt_val{0.06f}; to double amt_val{0.06}; it will work, but i fail to understand what's really going on beneath the surface. Why does the program give 0 to amt_needed_cents above, and 1 in the other cenario?
// Example program
#include <iostream>
using namespace std;
int main()
{
const double nickels{0.05};
const float cents{0.01};
int amt_needed_nickels{0}, amt_needed_cents{0};
double amt_val{0.06}; // for 0.06 cents
double amt_val_copy{amt_val};
amt_needed_nickels = amt_val / nickels;
if(amt_needed_nickels != 0)
amt_val -= (nickels * amt_needed_nickels);
amt_needed_cents = amt_val / cents;
cout << "If it costs $" << amt_val_copy << ", you'll need:\nNickels: " << amt_needed_nickels << "\nCents: " << amt_needed_cents << "\n";
cout << "I know this is correct, but I don't know what the compiler is thinking with this as compared to the other\n\n";
}
Upvotes: 1
Views: 604
Reputation: 23498
Floating point calculations are not precise, when doing math you get the very small difference, which will break your program if you try to check for an exact equality of the numbers. For example, 1.2 * 3
is not exactly 3.6
(note that this doesn't mean all calculations are inexact: e.g. multiplication by any power of 2
is always exact: things like 1.5 * 2
and 1.1 / 4
always give the best answer possible). This is because decimal fractions like 1/10
and 1/100
are not exactly representable in binary, which is an issue when our coins are based on 1/100
(the cent).
In your program, you should instead represent coins as an integers by converting all values to cents, then everything will work just fine. That is, you know that the largest denominator you will ever deal with is 100
, so you may as well multiply everything by 100
. So, nickels
is going to be 5
, cents
is going to be 1
and all calculations will be precise.
To avoid any confusion, here's your code in integers:
int dollars = 100, nickels = 5, cents = 1;
int amt_needed_dollars = amt_val / dollars;
amt_val -= amt_needed_dollars * dollars;
int amt_needed_nickels = amt_val / nickels;
amt_val -= amt_needed_nickels * nickels;
// skipped dividing by cents, because it's '1' anyway
int amt_needed_cents = amt_val;
Upvotes: 4
Reputation: 343
I'm not the best with c++ but it looks like the problem is here:
int amt_needed_nickels{0}, amt_needed_cents{0};
amt_needed_nickels = amt_val / nickels;
Try changing amt_needed_cents to a float or double the parsing/rounding it later. Unlike other languages (like JS) c++ is annoying when trying to convert types like that. You are dividing two floats to an int which probably truncates the decimal.
Upvotes: -1