2012-10-03 85 views
1

我正在寫一個C++類,它在向量中存儲一些double值(稱爲mpValues)並計算它們的平均值。構造時,值數組爲空,因此執行此計算將返回0.0/0.0。C++最好的方法來處理零除

我決定詢問零值的平均值是一個錯誤。因此,最好返回NaN並顯示一條錯誤消息,以便用戶知道該問題。 的代碼看起來是這樣的:

double Average::CalculateAverage() const 
{ 
    if(mpValues->size() == 0){ 
     std::cerr << "Instance of Average at: " << this << " contains no values.\n" 
        << "In this case the arithmetic mean is defined as NaN." <<std::endl; 

     return 0.0/0.0; 
    } 
    else{ 
     ...calculate the arithmetic mean 
    } 
} 

這是一個明智的做法,或者你有更好的建議?通常情況下,我不會那麼挑剔,但這是對工作機會的考驗,所以我想避免做出錯誤的決定。

在此先感謝!

+1

但是你怎麼檢查那個南?如果它是一個錯誤條件,那就拋出一個異常或者將布爾返回參數設置爲false。 – acraig5075

+1

@michael爲什麼只有一個*平均值*的整個班?這是過度勞累的尖叫聲。 –

+1

您的返回0.0/0.0;通常不會返回NaN ...它通常會生成一個CPU陷阱/中斷/異常(這不是可以通常方式捕獲的C++異常)。 –

回答

6

標準選項是返回NaN,拋出異常或返回選項,如boost :: optional。每個人都有優點和缺點,已經有很多人進行了詳細的評估。只是不要在函數中顯示錯誤消息,因爲這違反了single responsibility principle

+0

+1提到三種流行的解決方案,並建議不要在功能內打印。 –

+0

感謝大家對我們的建議,我決定現在就去例外。 – michael

0

將退貨類型更改爲boost::optional<double>,我建議。

Link to Doc

3

你已經回答了這個問題:

我決定,要求零個值的平均值是錯誤的。

因此,不需要返回NaN或處理零分割。你可以創建自己的異常類(例如EmptyVectorError)並拋出並捕獲它。

+0

+1。這正是採取的正確方法。創建一個新的異常,並在你的代碼中處理它。它只有一個含義,只能在這個特定的情況下發生。 –

-1

你有2個選擇 - 要麼返回NaN要麼拋出異常。你應該做什麼,取決於使用情況。

1)客戶端只顯示平均值:然後我會選擇簡單地返回NaN。這樣,客戶端就不必爲他不打擾的東西寫錯誤處理代碼。

2)客戶使用均值計算新值:然後很難。通過拋出異常,你迫使他明確地處理它。這可能是件好事。另一方面 - 據我所知,雙倍數值NaN可用於計算。這也取決於你的其餘工作。如果你總是使用例外,你也應該使用例外。如果您始終使用錯誤代碼,則應使用NaN。如果你混合 - 你應該清理它。

P.S .:我不會寫0.0/0.0,而是用std::numeric_limits代替。它更容易閱讀。

+0

-1 NaN不是一個好主意。如何生成一個?如果你調用'0.0/0.0',行爲取決於錯誤設置等。我們正在討論C++和NaN *生成NaN的目的似乎是一個愚蠢的想法。 – Walter

+1

「你怎麼生成一個?」 - 如果實現完全支持NaN,則可以使用'std :: numeric_limits :: quiet_NaN()'或'signalling_NaN()'生成一個。當然,對於那些根本不支持NaN的實現來說,這仍然沒有幫助,因爲你根本無法返回NaN。這是C++允許的,但不是IEEE允許的。 –

1

這是一個C++問題,所以我們應該給出一個C++的答案。從單責任原則(由Don Reba提到),我們得出結論,從您的函數內報告錯誤並不合適。有兩個主要選項。

明確規定,呼喚你的average(container)有一個空的容器是未定義行爲(UB)。這是C++ std庫中許多算法的標準做法。它允許您忽略空容器的可能性,並返回sum/size()。您可以在調試模式下添加assert(size()>0);(或類似)。

明確允許在API中的空容器(我認爲這是你想要什麼)。在這種情況下,返回sum/size()是不合適的。它可能會返回NaN或觸發信號,具體取決於錯誤設置,但即使是NaN也不容易捕捉(我認爲isnan()不是標準庫函數)。所以你必須以某種方式以一種乾淨的方式返回未定義的結果。這可以通過拋出一個適當的異常或返回一個類型來完成,比如boost::optional<>(由usta建議),明確允許一個未定義的值不是錯誤(與NaNdouble不同)。

我認爲在C++中拋出異常是最合適的方法(如果你選擇了選項2)。

+1

在C++ 11中增加了'isnan',這是值得的。 IEEE浮點有意提供了對非值進行編碼的方法,本質上它與'boost :: optional'有一些相同的設計目標,並且減輕了對它的需求,因爲IEEE是爲C和彙編設計的,不僅僅是語言就像C++一樣。但是C++沒有強制要求IEEE,所以... –

+0

@SteveJessop感謝你的澄清(在這個問題的所有評論中)。 – Walter

相關問題