ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

浮点数计算常见错误1.#INF, 1.#IND和#QNAN

2021-04-24 15:02:01  阅读:315  来源: 互联网

标签:std EM QNAN 浮点数 .# Precision state inf


编程时,可能会从您的代码中产生某些错误条件。如果编译器捕获任何编译错误,它将停止编译并告诉您错误所在位置。编译器还可能会对某些构造发出警告,这些构造可能会或可能不会在运行期间给您带来问题。

以下是您作为程序员在执行浮点算术(任何加法、减法、乘法和除法)时应注意的一些浮点条件,即(QNAN 和 SNAN)条件和错误。

 

正数负数意义
1.#INF-1.#INFInfinity无穷大
1.#SNAN-1.#SNANSignalling NaN
1.#QNAN-1.#QNANQuiet NaN
1.#IND-1.#IND

Indefinite / Indeterminite NaN

不是一个数,未定值

#NaN

C++中代表不是数字。它是一种用浮点描绘未定义或未指定值的价值。NAN 的概念于 1985 年由 IEEE 754 浮点标准引入,其中还给出了无穷大的概念。NaN

#QNaN和#SNaN

有两种,安静和信号。两者非常相似,在大多数情况下都是相同的。与MSVC,信号导航(sNaN)默认情况下是安静的导航。他们不会提出任何硬件例外(因为所有的浮点例外),你不会注意到任何错误,直到打印出结果,但模拟惨败。

#INF

C++表示"无穷大"。由于浮点数的有限性(对于双精度浮点数),无限以有限的值表示。INF32-bit64-bit

当由此产生的数字溢出或溢出浮点数的容量时,就会出现此类错误条件/值。换句话说,值太大或太小,不能表示为浮点值。

因此,该值显示为。#INF

  • 1.#INF-如果结果是一个太大的正数。
  • -1.#INF-如果结果是一个太大的负数。

最简单的使用方式得到一个无限的数字是要求它。

#include <limits>   // Infinite auto positive_inf = std::numeric_limits<double>::infinity(); auto negative_inf = positive_inf * -1;   std::cout << "Positive infinity: " << positive_inf << std::endl; std::cout << "Negative infinity: " << negative_inf << std::endl;   // Output // Positive infinity: 1.#INF // Negative infinity: -1.#INF   // Or division by zero double zero = 0.0; double divbyzero = 1.0 / zero;   // Output // Division by zero: 1.#INF

任何具有无穷大的操作都会产生另一个无限值,因此它的行为就像瘟疫一样,在迭代模拟中传播,杀死模拟。

std::cout << "Add: " << add << " Sub: " << sub << " Mul: " << mul << " Div: " << div << std::endl;   // Output: // Add: 1.#INF Sub: 1.#INF Mul: 1.#INF Div: 1.#INF

在执行流格式化时,无穷大数字可能会混乱,并可能显示一些不预期的东西。

#include <iomanip>   // Formatting (scientific) for(size_t i=0; i<10; i++) {     std::cout << "Precision: " << std::scientific << i << std::setprecision(i) << " inf: " << positive_inf << std::endl; }   // Output // Precision: 0 inf: 1.#INF00e+000 // Precision: 1 inf: 1.$e+000 // Precision: 2 inf: 1.#Je+000 // Precision: 3 inf: 1.#IOe+000 // Precision: 4 inf: 1.#INFe+000 // Precision: 5 inf: 1.#INF0e+000 // Precision: 6 inf: 1.#INF00e+000 // Precision: 7 inf: 1.#INF000e+000 // Precision: 8 inf: 1.#INF0000e+000 // Precision: 9 inf: 1.#INF00000e+000   // Formatting (fixed) for (size_t i=0; i<10; i++) {     std::cout << "Precision: " << std::fixed << i << std::setprecision(i) << " inf: " << positive_inf << std::endl; }   // Output // Precision: 0 inf: 1 // Precision: 1 inf: 1.$ // Precision: 2 inf: 1.#J // Precision: 3 inf: 1.#IO // Precision: 4 inf: 1.#INF // Precision: 5 inf: 1.#INF0 // Precision: 6 inf: 1.#INF00 // Precision: 7 inf: 1.#INF000 // Precision: 8 inf: 1.#INF0000 // Precision: 9 inf: 1.#INF00000

固定精度0是非常危险的!没有迹象表明这是一个无限的数字!

#IND

当结果无法确定时出现此类错误。对于某些输入未定义的数学方法来说,情况尤其如此。#INDNaNacossqrt

 

例如,零除以零()在数学领域或。浮点也一样,产生了一个不确定的数字。0.0 / 0.0#IND

double a = 0.0; double b = 0.0 / a; double negative_sqrt = sqrt(-1);   std::cout << "0.0/0.0 = " << b << std::endl; std::cout << "sqrt(-1) = " << negative_sqrt << std::endl;   // Output // 0.0/0.0 = -1.#IND // sqrt(-1) = -1.#IND

捕获错误

有几个方法可以捕获 NAN,有些方法需要附加调试器才能获得最佳结果。

方法1:比较。

当将变量与自身进行比较时,它会产生与正常数字相反的结果。

double inf = std::numeric_limits<double>::infinity(); double nan = std::numeric_limits<double>::quiet_NaN(); double ind = sqrt(-1);   if (nan != nan)     std::cout << "nan != nan" << std::endl;   if (ind != ind)     std::cout << "ind != ind" << std::endl;   if (inf != inf)     std::cout << "inf != inf" << std::endl;   // Output // nan != nan // ind != ind // std::isnan(nan) is true // std::isnan(ind) is true

方法2(C++11):使用标准。

C++11引入了几种方法来确定一个值是否是一个或不是,这些值居住在名称空间中std::

// Method 2, std::isnan   if (std::isnan(nan))     std::cout << "std::isnan(nan) is true" << std::endl;   if (std::isnan(ind))     std::cout << "std::isnan(ind) is true" << std::endl;   if (std::isnan(inf))     std::cout << "std::isnan(inf) is true" << std::endl;   // Output // std::isnan(nan) is true // std::isnan(ind) is true

方法3(MSVC):控制浮点控制词。

使用_controlfp_control87将改变浮点控制词,基本上使计算机在浮点异常发生时发出硬件例外。MSVC 的默认值是静音浮点异常,并有可能默默销毁模拟。

我个人建议打开所有浮点例外,以便所有(或大多数)案件可以审查和代码更加强大

这个用法有点违反直觉,但过了一会儿你会习惯的。以下是对我有效的东西。

// According to the docs, always clear fp control word auto state = _clearfp(); state = _control87(0,0);

这将重置,并获得当前的浮点控制字状态。

 

有了这个,我们可以根据自己的喜好修改浮点控制词。

// This will turn ON FPE for zerodiv state = _control87(state & ~_EM_ZERODIVIDE, _MCW_EM);   // This WILL NOT fail const double sqrtneg = sqrt(-1);   // This WILL fail due to zerodiv const double zero = 0.0; const double zerodivresult = 1.0 / zero;

838

否则,我们可以用#IND_EM_INVALID与indeterminate ()退出。

// This will turn on FPE for #IND state = _control87(state & ~_EM_INVALID, _MCW_EM);   // This WILL fail const double sqrtneg = sqrt(-1);   // This WILL NOT fail and it'll produce #inf const double zero = 0.0; const double zerodivresult = 1.0 / zero;

392

如果你想打开两个或两个以上的FPEs,你必须做一些算术来设置正确的开关。

// This will turn on FPE for #IND and zerodiv state = _control87(state & ~(_EM_ZERODIVIDE|_EM_INVALID), _MCW_EM);

如果你想把所有的FPEs,这将做到这一点。

// All FPEs state = _control87(state & ~(_EM_INEXACT|_EM_UNDERFLOW     |_EM_OVERFLOW|_EM_ZERODIVIDE|     _EM_INVALID|_EM_DENORMAL), _MCW_EM);

要找出哪些浮点异常是活跃的,此片段将有所帮助。

bool inexact    = 0 == (state & _EM_INEXACT); bool underflow  = 0 == (state & _EM_UNDERFLOW); bool overflow   = 0 == (state & _EM_OVERFLOW); bool zerodiv    = 0 == (state & _EM_ZERODIVIDE); bool invalid    = 0 == (state & _EM_INVALID); bool denorm     = 0 == (state & _EM_DENORMAL);   std::cout << std::boolalpha << "Will break on: n"     << "Inexact: " << inexact << "n"     << "Underflow: " << underflow << "n"     << "Overflow: " << overflow << "n"     << "Zerodiv: " << zerodiv << "n"     << "Invalid: " << invalid << "n"     << "Denormal: " << denorm << "n";   // Output // Will break on: // Inexact: false // Underflow: false // Overflow: false // Zerodiv: true // Invalid: true // Denormal: false

 

标签:std,EM,QNAN,浮点数,.#,Precision,state,inf
来源: https://blog.csdn.net/novanova2009/article/details/116091002

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有