首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何让C++ signaling_nan()抛出异常,而不需要if测试?

如何让C++ signaling_nan()抛出异常,而不需要if测试?
EN

Stack Overflow用户
提问于 2021-07-02 21:48:36
回答 1查看 290关注 0票数 0

我正在尝试使用signaling_nan()来自动抛出一个异常,如果在设置之前使用了其值将在初始化后设置的变量。

我已经尝试过使用浮点异常功能,但是该解决方案需要对FE_INVALID进行if测试,我想避免这种测试。

下面我包含了一个简化的示例代码。在代码中,我有一个带成员double x的A类,我将其初始化为构造函数中的signaling_nan()。这个类还包括一个函数divide_by_x,它将类成员x传入的参数分开,我创建了一个对象A a1,并调用a1.divide_by_x(10.0)。我期望程序抛出一个异常,但是它继续并返回nan作为divide_by_x函数调用的值。

在示例代码中,我在程序末尾为FE_INVALID浮点异常提供了一个if测试,如果x是用一个quiet_nan()而不是无效的signaling_nan() FE_INVALID初始化的,那么它的输出会沿着预期的行变化。这表明signaling_nan()确实在生成浮点异常,但是程序继续执行。

代码语言:javascript
复制
#include<iostream>
#include <utility>
#include <limits>
#include <float.h>
#include <signal.h>
#include <fenv.h>

using namespace std;

class A
{
public:

  // Constructor
  A():x(std::numeric_limits<double>::signaling_NaN()){}
  //A():x(std::numeric_limits<double>::quiet_NaN()){}

  // Set x
  void set_x(double x_value) { x = x_value; }

  // Divide number by x
  double divide_by_x(double other_number)
  {
    double result = other_number/x;

    return result;
  }
  
  // Member
  double x;
};
  
int main(void)
{
  feclearexcept(FE_ALL_EXCEPT);
  
  A a1;

  double before_setting_x;

  before_setting_x = a1.divide_by_x(10.0);

  if (fetestexcept(FE_INVALID))
        printf("FE_INVALID\n");
    else
        printf("Not invalid\n");
  
 return 0;
}

用signaling_nan():初始化x的signaling_nan输出

FE_INVALID

用quiet_nan():初始化x的quiet_nan输出

不无效

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-07-03 00:22:40

因此,有很多方法可以解决这个问题:

自定义类,这些类在操作中检查FPE

最简单的方法就是编写一个包装类,它检查浮点异常,然后不必在以后处理它,所有内置的数值操作。

代码语言:javascript
复制
#include <exception>
#include <fenv.h>

class FloatingPointException: public std::exception {
    const char* what() const throw() {
        return "Exception raised in floating-point operation.";
    }
};

class F64 {
public:
    F64(double f): m_f(f) {}
    F64(const F64 &other): m_f(other.m_f) {} 
    F64(F64 &&other): m_f(other.m_f) {}
    F64& operator=(const F64& other) { m_f = other.m_f; return *this; }
    F64& operator=(F64&& other) { m_f = other.m_f; return *this; }

    operator double() const { return m_f; }

    // This is where we use fenv.
    F64 operator*(F64 other) const {
        feclearexcept(FE_ALL_EXCEPT);
        auto result = m_f * other.m_f;
        if (fetestexcept(FE_INVALID)) {
            throw FloatingPointException();
        }
        return F64(result);
    }

    F64& operator*=(F64 other) {
        operator=(operator*(other));
        return *this;
    }

    // This is where we use fenv.
    F64 operator/(F64 other) const {
        feclearexcept(FE_ALL_EXCEPT);
        auto result = m_f / other.m_f;
        if (fetestexcept(FE_INVALID)) {
            throw FloatingPointException();
        }
        return F64(result);
    }

    F64& operator/=(F64 other) {
        operator=(operator/(other));
        return *this;
    }

    // Implement all other operations.
private:
    double m_f;
};

可养家糊口

另一种方法是在程序开始时使用feenableexcept

代码语言:javascript
复制
#include <fenv.h>
int main() {
    feenableexcept(FE_INVALID);
    ...
    return 0;
}

如果出现无效的浮点异常,这将生成SIGFPE。您还可以使用GCC扩展,因此这会自动发生在main之前。

代码语言:javascript
复制
#define _GNU_SOURCE 1
#include <fenv.h>
static void __attribute__ ((constructor)) trapfpe {
    feenableexcept(FE_INVALID);
}

您也可以将它与信号处理程序一起使用。

定制装配

我强烈建议不要这样做,因为它不会是可移植的(即使是在x86上,因为x87 FPU与使用SSE2的较新的x86 CPU不同。但是,您可以尝试使用内联程序集来检查浮点异常,尽管这可能是一个非常糟糕的主意。例如,处理x87 FPU状态寄存器是详细的这里

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68231535

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档