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



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

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

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

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.

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

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

避免这些类型的浮点gotcha的一种通用技术是使用任意精度的算术库。其中有很多,我对它们不够熟悉,无法推荐一个。当然,使用任意精度的数字会带来性能损失,但在您知道您的算法是一个瓶颈之前,进一步优化是不明智的。

如果您绝对必须使用浮点运算,那么与长浮点计算相比,有多种经验法则可以提高精度;查看一些数值方法文本以获取更多信息。还有大量关于浮点计算精度的研究,这些研究产生了一些相当酷的软件。

由于舍入问题,您永远不应该使用floatdouble来表示货币单位(它们不精确,当涉及到货币时,人们希望精确)。

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

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

根据您的输入,结果是:

31.129999999999999

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

class DecimalCurrencyUnit
{
    long   cents;
    public:
        DecimalCurrencyUnit()
            : cents(0)
        {}
        DecimalCurrencyUnit(long euros, long cent)
            : cents(euros * 100 + cent)
        {}
        friend std::ostream& operator<<(std::ostream& s, DecimalCurrencyUnit const& out)
        {
            return s << '€'
                     << (out.cents / 100) << "." 
                     << std::setw(2) << std::setfill('0') << (out.cents % 100);
        }
        friend std::istream& operator>>(std::istream& s, DecimalCurrencyUnit& in)
        {
            long euros;
            long cent;
            char s;
            char x;
            if ((s >> s >> euros >> x >> cent) && s == '€' && x == '.' && cent < 100)
            {
                in.cents = euros * 100 + cent;
            }
            else
            {
                s.setsetate(std::ios::bad);
            }
            return s;
        }
        // Add standard operators here for *+/- etc.
}

相关内容

  • 没有找到相关文章

最新更新