更改关联性时,答案略有不同

时间:2016-05-02 12:43:48

标签: c++ floating-point floating-accuracy associativity

使用以下简单的C ++练习

[========                                ] 17/80 ( 21%) 63 to go

如果输入是,则可以获得两个不同的答案,例如31.13:

#include <iostream>
using namespace std;
int main() 
{
    int euro, cents_v1, cents_v2, do_again;
    double price;

    do_again = 1;

    while(do_again != 0){

        cout<<"Insert price in Euro with cents"<<endl;
        cin>>price;

        euro = price;
        cents_v1 = price*100 - euro*100;
        cents_v2 = (price - euro) * 100;

        cout<<"Total: "<<euro<<" euro and "<<cents_v1<<" cents"<< endl;
        cout<<"Total: "<<euro<<" euro and "<<cents_v2<<" cents"<< endl;

        cout <<"\nDo it again? 1: yes, 0: no."<<endl;
        cin>>do_again;

    }
    return 0;

}

如何处理这个问题?在更复杂的情况下,编程是否有规则来避免或控制这个问题?

2 个答案:

答案 0 :(得分:3)

浮点加法和乘法是可交换的,但不是关联的或分配的。因此,正如您所观察到的,cents_v1cents_v2实际上可能代表不同的值。

避免这些类型的浮点陷阱的一种通用技术是使用任意精度的算术库。有quite a few of these,我不太熟悉它们推荐一个在另一个上面。当然,使用任意精度数会导致性能损失,但在您知道算术是瓶颈之前,进一步优化是不明智的。

如果绝对必须使用浮点运算,那么有很多经验法则可以提高长浮点计算的准确性;查看一些数值方法文本以获取更多信息。对浮点计算的准确性进行了大量研究,产生了一些rather cool software

答案 1 :(得分:1)

由于四舍五入问题,您不应该使用Insert price in Euro with cents 31.13 Total: 31 euro and 13 cents Total: 31 euro and 12 cents Do it again? 1: yes, 0: no. float来代表货币单位(它们不准确,而且涉及到人们想要确切的钱)。

尝试在代码中添加以下行:

double

输入结果为:

std::cout << std:: setprecision(17) << price << "\n";

所以你需要创建一个代表你钱的课程(不是个坏主意)。或者使用整数(因为整数总是精确的)。因此,将金额存储为美分的数量,而不是欧元的数量。然后在显示时只转换为欧元和美分。

31.129999999999999