簡體   English   中英

使用 static_cast 從 int 轉換為 float 時輸出不正確<float> C++

[英]Incorrect output when converting from int to float with static_cast<float> c++

我不明白為什么我的輸出是錯誤的。 我附上了我的代碼和我的結果(突出顯示了問題)

我正在向 VendingMachine 類中的 insertCoin 函數添加一個硬幣。 一旦我向這個函數添加 10 美分,它就會打印出錯誤-> 不接受 10 美分。 我正在使用 static_cast 將輸入轉換為浮點數。 我花了一些時間在這上面,在這一點上,我覺得我看不到這個問題,可能是因為我不明白一些概念。

也作為快速背景,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;  
};

在此處輸入圖片說明

為什么它沒有按預期工作?

這不是特定於 C++,而是特定於浮點數。

C++ 標准沒有說明浮點是如何編碼的。 但一般來說,浮點數是使用兩個小數的冪進行編碼的。 在這些方案中,一些十進制數沒有精確匹配,而是使用最接近的匹配,並帶有一些近似值。

例如,最流行的編碼可能是IEEE-754 這個不錯的在線轉換器顯示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)

在線演示

如何解決?

正如有人在評論中建議的那樣,這里最好的選擇是使用整數並計算美分。 在這種計算中沒有浮點引起的近似值,所以對於金錢來說它是理想的。

一種解決方法是將所有浮點數對齊為doublefloat (通過向數字文字添加尾隨f )。 如果在某些計算中沒有舍入問題,這將在比較常量值時起作用。

另一種解決方案是替換嚴格相等比較,用不等式檢查兩個數字之間的差異是否非常小。 這是 Jason在另一個答案中提出的 epsilon 方法, 此處解釋的almost_equal()函數的幫助下比較這些值

不相關:不要使用size_t來表示錢。 這對讀者和維護者來說是一種誤導;-)。 如果你想要一個 unsigned int、一個 unsigned long 或一個 unsigned long long,就這么說。

您可以使用epsilon來比較浮點數,克服了很難精確地相等浮點數的事實,您必須使用“非常接近等於”。 有關更多詳細信息,請參閱此帖子: 浮動和雙重比較的最有效方法是什么?

我個人建議將代碼更改為以美分整數單位工作,以避免在整個代碼中實現“非常接近”模式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM