使用static_cast <float> c ++从int转换为float时输出不正确

问题描述

我不明白为什么我的输出出现错误。 我已附上我的代码和结果(突出显示了问题)

我在vendingMachine类的insertCoin函数添加一个硬币。 我向该功能添加10美分后,就会立即打印出错误->不接受10美分。 我正在使用static_cast将输入转换为float。我花了一些时间在这一点上,在这一点上,我觉得我看不到问题,可能是因为我不理解某些概念。

作为一个快速的背景知识,C ++还是一个新手,它试图使我的面向对象编程保持最新。 试图使自动售货机产品呵呵。 再次谢谢你!

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <utility>
#include <stdlib.h> 
using namespace std;

class Item
{
    private:
        string m_name;
        float m_cost;
    public:
        Item(string t_name,float t_cost):m_name(t_name),m_cost(t_cost)
        {
            
        }
        string getName()
        {
            return m_name;
        }
        float getCost()
        {
            return m_cost;
        }
};
class vendingMachine
{
    private:
        vector<Item> m_totalItems;
        unordered_map<string,Item>m_products;
        float m_remainingCharges{0};
        float m_moneyInserted{0};
        size_t itemCount{0};
    public:
        vendingMachine()
        {
            
        }
        void addItemTovendingMachine(string t_name,size_t t_cost)
        {
            float temp=static_cast<float>(t_cost)/static_cast<float>(100);  
            Item item(t_name,temp);
            m_totalItems.push_back(item);
            m_products.insert(make_pair(t_name,item));
        }
        bool chooseProduct(string t_name)
        {
            for(auto item:m_totalItems)
            {
                if(item.getName()==t_name)
                {
                    m_remainingCharges=item.getCost();
                    return true;
                }
                itemCount++;
            }
            cout<<"Item not currently available: "+t_name<<endl;
            return false;
        }
        void insertCoin(size_t t_coin)
        {   
            float temp=static_cast<float>(t_coin);
            if(t_coin<=50)
            {
                temp/=100;
                cout<<temp<<endl;
            }
            if(temp==0.01 or temp==0.05 or temp==0.1 or temp==1.00 or temp==2.00 or temp==0.25 or temp==0.50)
            {
                m_moneyInserted+=temp;
                m_remainingCharges-=m_moneyInserted;
            }
            else
            {
                cout<<"Does not accept: "<< t_coin<<",please insert correct coin."<<endl;
                return;
            }
        }
        pair<Item,float> getProduct()
        {
            auto item=m_totalItems[itemCount];
            auto itemBack=m_totalItems.back();
            m_totalItems[itemCount]=itemBack;
            m_totalItems.pop_back();
            return make_pair(item,abs(m_remainingCharges));
        }
        
        float refund()
        {
            if(m_remainingCharges<0)
                return abs(m_remainingCharges);
            else
                return 0;
        }
        void resetoperator()
        {
             m_remainingCharges=0;
             m_moneyInserted=0;
             itemCount=0;
        }
};
int main()
{
    Item item("Candy",0.50);
    cout<<item.getName()<<" ";
    cout<<item.getCost()<<endl;
    vendingMachine machine;
    machine.addItemTovendingMachine("CANDY",10);
    machine.addItemTovendingMachine("SNACK",50);
    machine.addItemTovendingMachine("Coke",25);
    machine.insertCoin(10);
    machine.insertCoin(25);
    machine.insertCoin(50);
    machine.chooseProduct("CANDY");
    auto temp=machine.getProduct();
    cout<<temp.first.getName()<<endl;
    cout<<temp.second<<endl;
    machine.resetoperator();
    return 0;  
};

enter image description here

解决方法

为什么它不能按预期工作?

这不特定于C ++,而是特定于浮点数。

C ++标准没有说明如何对浮点进行编码。但通常,浮点数使用两个分数的幂进行编码。在这些方案中,一些十进制数字没有完全匹配,而是使用最接近的匹配,并带有近似值。

例如,最流行的编码可能是IEEE-754。此nice online converter表示0.1没有精确匹配。最接近的近似值是0.100000001490116119384765625

  • 如果您将此值打印出来,并且四舍五入,那么一切都会好起来的。
  • 但是,如果您比较==是否相等,则该值必须完全相同。不幸的是,不同的计算可能会产生不同的舍入。因此,您将获得两个不同的数字,非常接近0.1,但彼此不同。
  • 在您的情况下,字面值0.1不是浮点数:它是双精度值,比浮点数具有更高的精度,因此得出不同的近似值。

实用证据

如果您不确定,请尝试以下更改:

    if(t_coin<=50)
    {
        temp/=100;
        cout.precision(10);  // print more digits
        cout<<scientific<<"temp:"<<temp<<" vs.double "<<0.1
             <<" or float "<<0.1f<<endl;
        }

,然后尝试比较浮点数和浮点数:

    if(temp==0.01f or temp==0.05f or temp==0.1f 
        or temp==1.00f or temp==2.00f 
        or temp==0.25f or temp==0.50f)

Online demo

如何解决?

这里最好的选择是使用整数并计算分,如评论中的建议。在这种计算中没有浮点数引起的近似,因此对于金钱来说是理想的。

一种变通方法,它可以将所有浮点数与doublefloat对齐(通过在数字文字上添加尾随f)。比较常量值时,如果在某些计算中没有舍入问题,这将起作用。

另一种解决方案是用严格检查来代替严格相等比较,以检查两个数字之间的差异是否很小。这是Jason in the other answer提出的epsilon方法,该方法借助定义为here

的函数almost_equal()比较这些值

不相关:请勿使用size_t来表示货币。这对读者和维护者有误导作用;-)。如果要无符号整数,无符号长整数或无符号长整数,请这样。

,

您可以使用epsilon来比较浮点数,从而克服了很难精确地将浮点数等价的事实,您必须使用“非常接近”。请参阅此帖子以获取更多详细信息: What is the most effective way for float and double comparison?

我个人建议更改代码以整数美分工作,以避免在整个代码中实施“非常接近”模式。