4

我需要有关如何以标准方式检测浮点下溢的帮助和示例代码,而不使用第三方库和有符号和无符号的异常。我用谷歌搜索,发现各种作者都在谈论“逐渐下溢算不算下溢”?谁能解释一下什么是逐渐下溢?我需要检查这两种情况

感谢您的时间和帮助

4

4 回答 4

2

查看“逐渐下溢”的热门搜索结果并没有给出明确直接的答案,因此:

IEEE-754 二进制浮点数在它们的大部分范围内都有一个规则模式:有一个符号、一个指数和一个具有一定位数的有效位(24 位代表 32 位float,53 位代表 64 位double)。但是,图案必须在末端打断。在高端,对于最大指数来说太大的结果将变为无穷大。在低端,我们有一个选择。

一种选择是,如果结果低于最低指数,则将结果四舍五入为零。但是,IEEE-754 使用了一种不同的方案,称为逐渐下溢。最低指数保留用于与常规指数不同的格式。

对于普通指数,24 位有效数为“1”。后跟在有效位字段中编码的 23 位。当数为次正规数时,指数与最低正则指数具有相同的值,但 24 位有效数为“0”。其次是 23 位。这是逐渐下溢,因为随着数字变小,在我们达到零之前,它们的精度越来越低(有效数字中的更多前导位为零)。

渐进下溢有一些很好的数学性质,特别是a-b == 0当且仅当a == b. a-b == 0对于突然的下溢,即使ab不同,也有可能是因为a-b太小而无法以浮点格式表示。随着逐渐溢出,所有可能的值a-b, 对于小的ab, 都是可表示的,因为它们只是具有最低指数的有效数字的差异。

确定是否发生浮点下溢的另一个问题是允许实现(根据 IEEE-754 标准)基于舍入前后的测试报告下溢。在计算结果时,浮点实现实际上必须执行以下步骤:

  • 计算精确结果的符号、指数和有效位。
  • 将结果四舍五入以适合浮点格式。如果有效数字向上取整,这可能会增加指数。

该标准允许实现通过以下任一方式报告下溢:

  • 计算精确结果的符号、指数和有效位。
  • 指数是否小于正常范围?如果是,报告下溢。
  • 将结果四舍五入以适合浮点格式。如果有效数字向上取整,这可能会增加指数。

或者:

  • 计算精确结果的符号、指数和有效位。
  • 将结果四舍五入以适合浮点格式。如果有效数字向上取整,这可能会增加指数。
  • 指数是否小于正常范围?如果是,报告下溢。

因此,对于相同的计算,两种不同的浮点实现可能会返回关于下溢的不同报告。

(还有一些关于处理下溢的附加规则。上面会导致发出下溢异常信号。但是,如果未启用来自此异常的陷阱并且结果是精确的 [舍入没有改变任何东西],那么“下溢”将被忽略, 并且不引发下溢标志。如果结果不准确,则引发下溢并发出不准确的异常信号。)

于 2013-03-28T11:30:10.377 回答
1

检查“下溢”位的浮点状态字,或捕获下溢浮点异常信号。看:

http://www.gnu.org/software/libc/manual/html_node/FP-Exceptions.html

于 2013-03-28T05:56:20.503 回答
0
template <typename T>
class Real
{
  public:
    Real(T x) : x_(x) { }
    Real& operator/=(T rhs)
    {
        if (x_)
        {
            x_ /= rhs;
            if (!x_)
                do whatever you want for underflow...
        }
    }
    friend Real operator/(Real lhs, Real rhs)
        { return lhs /= rhs; }
    // similar for -= etc.
  private:
    T x_;
}
于 2013-03-28T06:00:43.570 回答
0

首先,您需要在构建中启用浮点异常的生成。其次,您必须在代码中捕获它们。

我做了这样的事情(使用Visual Studio)

    void translateFPException( unsigned int u, EXCEPTION_POINTERS* pExp )
    {
    unsigned int fpuStatus = _clearfp(); // clear the exception 
    switch (u)
    {
    case STATUS_FLOAT_DENORMAL_OPERAND: 
        throw fe_denormal_operand(fpuStatus);
    case STATUS_FLOAT_DIVIDE_BY_ZERO: 
        throw fe_divide_by_zero(fpuStatus);
    case STATUS_FLOAT_INEXACT_RESULT: 
        throw fe_inexact_result(fpuStatus); 
    case STATUS_FLOAT_INVALID_OPERATION: 
        throw fe_invalid_operation(fpuStatus);  
    case STATUS_FLOAT_OVERFLOW: 
        throw fe_overflow(fpuStatus);   
    case STATUS_FLOAT_UNDERFLOW: 
        throw fe_underflow(fpuStatus);  
    case STATUS_FLOAT_STACK_CHECK: 
        throw fe_stack_check(fpuStatus);    
    default:
        throw float_exception(fpuStatus);
    };
    }

void initializeFloatingPointExceptionHandling()
{
    unsigned int fpControlWord = 0x00;

    _clearfp(); // always call _clearfp before enabling/unmasking a FPU exception
    // enabling an exception is done by clearing the respective bit in the control word
    errno_t success = _controlfp_s( &fpControlWord, 
                                    0xffffffff^( _EM_INVALID 
                                               | _EM_ZERODIVIDE 
                                               | _EM_OVERFLOW
                                               | _EM_DENORMAL
                                               | _EM_UNDERFLOW
                                               | _EM_INEXACT), _MCW_EM );
    if (success != 0)
    {
        stringstream errStream;
        errStream << success << " " << __FILE__ << ":" << __LINE__ << std::endl;
        throw exception(errStream.str().c_str());
    }

    _se_translator_function old =_set_se_translator(translateFPException);
}
void enableAllFPUExceptions()
{
    unsigned int oldMask = 0x00000000;

    _clearfp();
    // enabling is done by clearing the respective bit in the mask
    _controlfp_s(&oldMask, 0x00, _MCW_EM);
}

void disableAllFPUExceptions()
{
    unsigned int oldMask = 0x00000000;

    _clearfp();
    // disabling is done by setting the respective bit in the mask
    _controlfp_s(&oldMask, 0xffffffff, _MCW_EM);
}

然后您必须编写自己的异常(也只是摘录,但您应该了解概念)

    class float_exception : public exception
{
public:
    float_exception(unsigned int fpuStatus);

    unsigned int getStatus();
protected:
    unsigned int fpuStatus;
};

class fe_denormal_operand : public float_exception
{
public:
    fe_denormal_operand(unsigned int fpuStatus);
};
于 2013-03-28T08:58:16.390 回答