2016-05-05 38 views
2

任何人都可以解釋爲什麼這段代碼不會產生下溢異常(在MSVC 2013和gcc @ coliru上)?從平均函數返回的值低於DBL_MIN爲什麼這不會產生雙重下溢?

#include <float.h> 
#include <iostream> 
#include <iomanip> 
#include <limits> 

const size_t g_testValueCount = 10; 
const double g_testValues[g_testValueCount] = { DBL_MIN, 0 }; 

double unsafeAverage(const double* testValues, size_t testValueCount) 
{ 
    double result = 0; 
    for (size_t testValueIndex = 0; testValueIndex < testValueCount; ++testValueIndex) 
    { 
     result += testValues[testValueIndex]; 
    } 
    return result/testValueCount; 
} 

int main(int argc, char** argv) 
{ 
    std::cout << "DBL_MIN = " << std::setprecision(std::numeric_limits<double>::digits10) << DBL_MIN << std::endl; 
    try 
    { 
     std::cout << " AVG = " << std::setprecision(std::numeric_limits<double>::digits10) << unsafeAverage(g_testValues, g_testValueCount) << std::endl; 
    } 
    catch (...) 
    { 
     std::cout << "unsafeAverage caught an exception!" << std::endl; 
    } 
    return 0; 
} 
+0

看看這個功能:http://en.cppreference.com/w/cpp/numeric/fenv/fetestexcept'fetestexcept' –

+0

@TommyA -thanks,我沒有意識到這一點。是的,下溢的異常標誌被設置,這就解釋了一切。 –

回答

5

主要有兩個原因,你不抓下溢例外:

  • 浮點異常不是C++異常,所以¹in一般來說,你不能用catch(...)抓住他們。

  • MSVC的默認浮點下溢行爲(推測在Coliru上使用g ++)會產生非規範值或零。反規範是一個低於普通最小值的值,具有較少的有效位。隨着有效位的數量變爲零,你會得到一個實際的零。


用C++ 11,以後你可以檢查通過C99 fetestexcept功能浮點錯誤。

這裏是你的代碼重寫,使用這樣的檢查:

#include <float.h> 
#include <iostream> 
#include <iomanip> 
#include <limits> 
#include <limits.h> 
using namespace std; 

#include <fenv.h> 

const size_t g_testValueCount = 10; 
const double g_testValues[g_testValueCount] = { DBL_MIN, 0 }; 

auto unsafeAverage(const double* const testValues, int const testValueCount) 
    -> double 
{ 
    double result = 0; 
    for(int i = 0; i < testValueCount; ++i) 
    { 
     result += testValues[i]; 
    } 
    return result/testValueCount; 
} 

auto main() -> int 
{ 
    cout << setprecision(numeric_limits<double>::digits10); 
    cout << "DBL_MIN = " << DBL_MIN << endl; 
    try 
    { 
     feclearexcept(FE_ALL_EXCEPT); 
     auto const result = unsafeAverage(g_testValues, g_testValueCount); 
     if(fetestexcept(FE_ALL_EXCEPT)) 
     { 
      throw std::runtime_error("Oopsie daisy!"); 
     } 
     cout << " AVG = " << result << endl; 
    } 
    catch(...) 
    { 
     cerr << "!unsafeAverage caught an exception" << endl; 
     return EXIT_FAILURE; 
    } 
} 

注:
¹儘管Visual C++了,作爲20世紀90年代

+0

關於第一點 - 我如何捕捉並處理下溢異常呢?至於第二,那麼 - 我預計至少會給我一個零。問這個問題的原因是我想做一個「安全」的平均函數,但現在我甚至不能觸發這個例外,只是出現了一個不好的例子:D –

+0

只是出於好奇,是否有任何真正的原因,你爲什麼想要使用函數返回原語的尾隨返回類型格式?或者你只是試圖使示例複雜化超過需要? :) –

+0

@TommyA:你的問題對我沒有意義,我很抱歉。使用兩種不同的語法明顯比使用兩種不同的語法更復雜,與您的假設/斷言/任何相反。 –

3

語言擴展假設你是使用C++ 11或更新版本,您可以使用fetestexcept函數來測試浮點異常。通過將FE_UNDERFLOW常數傳遞給函數來測試下溢異常。

+0

不錯的功能。這樣您可以拋出自己的用戶定義的異常並完全避免SEH。 –

相關問題