[英]Why doesn't this produce a double underflow?
任何人都可以解釋為什么這個片段不會產生下溢異常(在MSVC 2013和gcc @coliru上)? 從average函數返回的值低於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;
}
您沒有遇到下溢異常的兩個主要原因:
浮點異常不是C ++異常,所以一般情況下你不能用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年代將其作為語言擴展
假設您使用的是C ++ 11或更高版本,則可以使用fetestexcept
函數測試浮點異常。 通過將FE_UNDERFLOW
常量傳遞給函數來測試下溢異常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.