双打不能正确减去小数

时间:2013-10-16 15:29:15

标签: c++ double precision subtraction decimal

我正在编写类似轮盘赌的C ++命令行程序。用户可以输入用于下注的小数值/数字。我正在使用双类型变量来实现这一点。但是,如果我以1美元开始,然后输掉0.23美元,那么下注0.55美元而输,然后下注0.07美元又输了,我不能下注0.15美元,即使程序声称我实际上有0.15美元美元(你不能赌更多的钱)。看来程序错误地减少了。不过,我仍然可以下注0.149美元。为了它的价值,我使用stringstream将用户的投注输入转换为双类型值。有人能解释一下这里发生了什么吗?

这是我的代码:

#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;
}

2 个答案:

答案 0 :(得分:2)

这不是因为程序减去错误 - 这是因为二进制分数和小数分数不是“完全数学上兼容” - 有限小数分数通常是无限周期二进制分数。

因此,对于像0.15这样的一些小数部分,存在几个有效的双重近似,因为减法的结果是你得到其中一个(A),并且从字符串“0.15”转换的结果你得到另一个(B)。而事故B似乎大于A。

你应该使用整数美分而不是双美元来保持精确的十进制舍入。更一般的解决方案是使用一些十进制数类(如this),它可以使用整数轻松实现小数分数运算。

一些十进制(和二进制)数字类实现arbitrary precision arithmetic - 它解决了固定点部分大于硬件支持的双重类型的任务。在规定舍入为美分(2位小数)的应用程序中,您不需要这样做。

答案 1 :(得分:0)

舍入错误会对数学密集型程序造成严重破坏,因为数学运算可能会使错误复杂化。

http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/