Reputation: 451
I'm writing a Roulette-like C++ command-line program. The user may input decimal values/numbers for betting. I'm using double-type variables to make this possible. However, if I for example start with 1 dollar, then 0.23 dollars and lose, then bet 0.55 dollars and lose, and then bet 0.07 dollars and lose again, I can't bet 0.15 dollars, even though the program claims I actually have 0.15 dollars (you can't bet more money than you have). It appears the program is incorrectly substracting. However, I still can bet 0.149 dollars. For what it's worth, I use stringstream to convert the user's betting input to a double-type value. Can somebody explain what is going on here?
Here is my code:
#include <iostream>
#include <sstream>
using namespace std; //Std namespace.
void string_to_number(string input, double& destination);
class Roulette {
private:
int randoms;
double money, choice, bet;
string input;
public:
int play = 0;
void start_amount() {
cout<<"How much money do you have?: ";
getline(cin, input);
string_to_number(input, money);
}
void betting() {
cout<<"How much money would you like to bet?: ";
getline(cin, input);
string_to_number(input, bet);
while (bet > money) {
cout<<"You can't bet more money than you have ("<<money<<" dollars). Please enter again: ";
getline(cin, input);
string_to_number(input, bet);
}
}
void choose_number() {
cout<<"Which number do you choose? (0-35): ";
getline(cin, input);
string_to_number(input, choice);
}
void random_number() {
cout<<"The wheel is spinning..."<<endl<<flush;
randoms = (rand())%36;
}
void scenarios() {
cout<<"The wheel shows number "<<randoms;
if (randoms == choice) {
money += bet;
cout<<", which means that you win "<<bet<<" dollars! You currently have "<<money<<" dollars."<<flush<<endl;
}
else {
money -= bet;
cout<<", which means that you lose "<<bet<<" dollars. You currently have "<<money<<" dollars."<<flush<<endl;
}
}
};
int main(int argc, const char * argv[])
{
srand(unsigned(time(0)));
Roulette a;
a.start_amount();
while (a.play == 0) {
a.betting();
a.choose_number();
a.random_number();
a.scenarios();
}
return 0;
}
void string_to_number(string input, double& destination) {
stringstream convert(input);
if ( !(convert >> destination) )
destination = 0;
}
Upvotes: 3
Views: 2911
Reputation: 4727
It is advised to not use floats for monetary calculations. Floats become imprecise quite quickly with big numbers due to their small size.
For monetary calculations, you may use Integers with a fixed scale (for example 100 becomes one dollar). This way you have 100% accuracy in the amount of decimal places you need.
Upvotes: 0
Reputation: 33
For me I tried first to move out decimals by multiplying both by 100, for example, 0.99 will become 99. Then after subtracting, I simply put back the decimal point by dividing it by 100.
Upvotes: 1
Reputation: 2736
This is not because program is subtracting wrong - it is because binary fractions and decimal fractions are not "fully mathematically compatible" - finite decimal fractions are often infinite periodic binary fractions.
So, for some decimal fractions like 0.15 there exist several valid double approximations, as the result of subtraction you got one of them (A) and as the result of conversion from string "0.15" you got another one (B). And by accident B appeared greater than A.
You should use integer cents, not double dollars to keep precise decimal rounding. More general solution is using some decimal number class (like this), which readily implements decimal fraction arithmetic using integers.
Some decimal (and binary) number classes implements arbitrary precision arithmetic - it solves task of having fixed point part larger than of hardware supported double type. You do not need this in applications where rounding to cents (2 decimal digits) is prescribed.
Upvotes: 4
Reputation: 1838
Rounding errors can play havoc with math-intense programs, as mathematical operations can compound the error.
http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/
Upvotes: 1