由于C ++中double类型的准确性而导致的错误

时间:2017-03-29 13:25:00

标签: c++ double

我写了一堂课来计算我的金额。以下是代码简述。

class RMB
{
private:
    int yuan;
    int jiao;
    int fen;
    bool mark;
public:
RMB(int yu, int ji, int fe, bool mar = true)
    {
        yuan = yu;
        jiao = ji;
        fen = fe;
        mark = mar;
    }
    RMB(double money)
    {
        int money1 = int(money * 100);
        yuan = money1 / 100;
        fen = money1 % 10;
        jiao = (money1 - yuan * 100 - fen)/10;
        if (money < 0) mark = 0;
        else mark = 1;
    }
    operator double()
    {
        double money = yuan + double(jiao) / 10 + double(fen) / 100;
        if (mark == false) return -money;
        return money;
    }
};
int main()
{
    RMB a(1,2,3);RMB b(2,3,4);
cout << "a + c = " << RMB(a + c) << endl;//assume I have override "<<" and ">>"

cout << "a - b = " << RMB(a - b) << endl;
}

但是当我测试我的代码时,它发生了:

a + c = 2 yuan 4 jiao 5 fen

a - b = -1 yuan -1 jiao 0 fen

我在VS2015中测试它,我已经调试过了,我看到double(a-b)的确切值是-1.199999998。那么我该如何修复这个bug呢?我该怎么办才能避免这类漏洞?

3 个答案:

答案 0 :(得分:10)

国家英里最容易做的事情就是使用积分类型来计算货币价值并以美分计算。将二进制浮点类型用于精确的十进制值永远不会结束。

如果你的编译器有它们,那么使用std::uint64_t作为类型,或std::int64_t如果你需要负数的概念。这对于用津巴布韦元表示的世界GDP来说已经足够大了。您甚至可以将其包装在class中以供将来验证。

C ++故意不提供十进制类型&#34;开箱即用&#34;。

答案 1 :(得分:0)

RMB(double money)
{
    int money1 = int(money * 100);

如果钱是负数,那么money1也是!

    yuan = money1 / 100;
    fen = money1 % 10;
    jiao = (money1 - yuan * 100 - fen)/10;

你的会员也一样!

    if (money < 0)
        mark = 0;
    else
        mark = 1;

另外存储标志(将在operator double中使用):

return mark ? money : -money;

假设您应该让您的成员为正(而我更喜欢未签名的成员):

RMB(double money)
    : mark(money >= 0)
{
    unsigned int money1 = (int)((mark ? money : -money) * 100);
    // ...
}

答案 2 :(得分:0)

我建议阅读: https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

为了更深入地对待这个主题,我建议: “每个计算机科学家应该知道的浮点运算”