Reputation: 1731
Aside from the obvious expected loss of fractional values, I don't see why this should happen...
Consider the following snippet from a homework assignment used to convert numerical digits to english phrases:
int main() {
float dollars;
cout << "Please supply a dollar amount between $0.01 and $9999.99 (without the dollar sign): ";
while (true) {
cin >> dollars;
if (cin.fail() || dollars < 0.01 || dollars > 9999.99) {
cin.clear();
cin.ignore();
cout << "You provided an invalid number. Please try again: ";
} else {
// Test code:
cout << "You entered: " << dollars << endl;
cout << "Times 100 without cast: " << dollars * 100 << endl;
cout << "Times 100 with cast: " << (int)(dollars * 100) << endl;
cout << "Cents: " << ((int)(dollars * 100)) % 100 << endl;
break;
}
}
printDollarsAsString(dollars);
return 0;
}
I've noticed that when supplying the value 9999.21
, the outputs of the second and third cout
statements in the else
block differ by 1. For example, here is the output when I run this code:
Please supply a dollar amount between $0.01 and $9999.99 (without the dollar sign): 9999.21
You entered: 9999.21
Times 100 without cast: 999921
Times 100 with cast: 999920
Cents: 20
How can I fix this so that the cents value is retrieved correctly? Is there a different approach I can take?
Upvotes: 0
Views: 1633
Reputation: 1299
Just because You've asked about different approach :)
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
...
std::string str_dollars;
char delim = '.';
std::vector<std::string> elems;
std::cin >> str_dollars;
std::stringstream ss(str_dollars);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
cout << "Cents: " << elems[1] << endl;
Upvotes: 1
Reputation: 1731
I ended up solving it with the help of round() for float in C++.
This also allows me to accept fractional cents, and I can round it accordingly. The following outputs what I expect:
cout << "Times 100 without cast: " << round(dollars * 100) << endl;
cout << "Times 100 with cast: " << (int) round(dollars * 100) << endl;
cout << "Cents: " << (int) round(dollars * 100) % 100 << endl;
Upvotes: 0
Reputation: 1960
This should fix it:
cout << "Times 100 without cast: " << dollars * 100 << endl;
cout << "Times 100 with cast: " << (int)(dollars * 100 + 0.5) << endl;
It is because of rounding.
full code:
} else {
// Test code:
cout << "You entered: " << dollars << endl;
cout << "Times 100 without cast: " << dollars * 100 << endl;
cout << "Times 100 with cast: " << (int)(dollars * 100 + 0.5) << endl;
cout << "Cents: " << ((int)(dollars * 100 + 0.5)) % 100 << endl;
break;
}
alternatively:
} else {
// Test code:
cout << "You entered: " << dollars << endl;
cout << "Times 100 without cast: " << dollars * 100 << endl;
cout << "Times 100 with cast: " << (int)round(dollars * 100) << endl;
cout << "Cents: " << ((int)round(dollars * 100)) % 100 << endl;
break;
}
Upvotes: 2
Reputation:
cout << "Times 100 without cast: " << dollars * 100 << endl;
cout << "Times 100 with cast: " << (int)(dollars * 100) << endl;
When you cast to int you are truncating the number, not rounding. In this case, the .21
cannot be storted exactly by binary floating point, because it actually comes out to a repeating number. The repeating number is slightly less than .21
. So when you multiply by 100 you get 999920.9...
which truncates to 999920
with the cast.
Upvotes: 6