C++ Builder 10.1 中 double -> unsigned __int64 类型转换的浮点异常

Floating point exception on double -> unsigned __int64 typecast in C++ Builder 10.1

我 运行 遇到一个问题,在 C++ Builder 10.1 Berlin 中某些双精度到无符号 __int64 类型转换抛出浮点无效操作异常($C0000090)。

我的应用程序允许用户输入,因此我需要能够处理任何值,但为简单起见,让我们使用以下示例:

double dValue = 9223372036854775807.0;
unsigned __int64 uhValue = (unsigned __int64) dValue;

虽然我可以在 try/catch 中处理这个异常,但这似乎破坏了 FPU 寄存器堆栈,后续的浮点操作将产生浮点堆栈检查异常。

以下问题报告描述了类似的问题并提供了可能的解决方法: http://qc.embarcadero.com/wc/qcmain.aspx/qcmain.aspx?d=119745

如果可能的话,我想阻止初始浮点异常。除了精度损失之外,存储在双精度值中的值在有效的无符号 __int64 范围内,因此我无法理解导致异常的原因。

在 typecast/conversion 或异常处理方面,我是否可以做一些不同的事情?

附带说明一下,上面的代码片段在 Visual Studio 中运行良好,并将 uhValue 设置为 9223372036854775808。

谢谢!

我只用旧的BDS2006所以我不能测试你的条件。但是你可以自己加载...像这样:

纯 64 位版本如下所示:

#pragma warn -8056
unsigned __int64 load(double x) // MSb sign(1),exp(11),1.0+mant(52) LSb
{
    int exp;
    unsigned __int64 y, *q = ((unsigned __int64*)(&x));

    exp = (*q >> 52) & 0x7FF; // extract exponent
    if (exp == 0x7FF)
        return 0; // here handle +/- inf value
    else
    { // extract mantissa and debiass exponent
        if (exp == 0x00) // denormalized form 0.000001
        {
            exp = -1024;
            y = *q & 0x000FFFFFFFFFFFFF;
        }
        else
        { // normalized form 1.000001
            exp -= 1023;
            y = *q & 0x000FFFFFFFFFFFFF;
            y |= 0x0010000000000000;
        }
    }
    // update your 64bit value with exponent shift and sign (this part is untested)
    exp -= 52;
    if (exp > 0)
        y <<= +exp;
    if (exp < 0)
        y >>= -exp;
    if (*q >= 0x8000000000000000)
        y = -y; // handle sign
    return y;
}
#pragma warn .8056

希望我没有做一些愚蠢的事情,因为我无法对其进行测试(我的编译器不支持 64 位算法)代码是从我的 arbnum class double 加载器中获取并更改为满足您的需求。

顺便说一句,我不完全相信 cast 是我之前在项目中遇到过类似问题的问题。我发现自己制作这些的两个主要原因:

  1. 使用 OpenGL,其中对 glBegin()/glEnd() 未正确平衡。

    缺少 glEnd() 一直在与其无关的代码中抛出 FPU 堆栈异常...

  2. BCB6 继承了 Borland C++ 引擎和编译器错误。

    我不使用 BCB6(我在 BDS2006)但是你们证实它也在那里(BCB5 很好),也可能在较新版本的 Borland 中也是如此。编译器生成的简单默认构造函数存在漏洞,对编译器和 C++ 引擎造成严重破坏。结合内存管理器错误(指针的双重删除不会抛出异常,而是使内存管理器无效),您可以随时使指针无效,甚至在不知不觉中覆盖内存中的部分代码......更不用说任何类型的偶然异常(最有可能是访问冲突),但在我深入了解这件事之前,我在某些项目中得到了与您相同的 FPU 废话(顺便说一句,您可以使用单个 fninit 指令来恢复 FPU 偶尔作为最后的手段)。

    有关更多信息和解决方法,请参阅:

    • bds 2006 C hidden memory manager conflicts