【问题标题】:Prevent "Float-point invalid operation" exception?防止“浮点无效操作”异常?
【发布时间】:2016-02-03 03:15:02
【问题描述】:

我正在使用 Visual C++ 将二进制数据加载到float,如下所示:

  double dValue;
  memcpy(&dValue, lpData, sizeof(dValue));

对于正常情况,这将正常工作。但是,在极少数情况下,当二进制数据损坏时,dValue 将无效,对其进行任何进一步的操作都会导致“浮点无效操作”异常。

我在调试器中检查了dValue,它显示为-1.#QNAN00000000000

为防止出现异常,我需要在从二进制数据加载dValue 后对其进行验证。我尝试使用:

  if (_finite(dValue))
  {
   … do some tasks…
  }

但无效的dValue 仍然会导致_finite 函数引发Float-point invalid operation 异常。虽然_finite(dValue) 会正确返回0,但是异常会分配到内存中。即使我取消分配它。过多的分配/解除分配仍然会耗尽系统资源。

因此,有没有办法在不引发任何异常的情况下检测双精度值的有效性?

【问题讨论】:

  • 在标准 C++ 中没有办法。也许您可以检查 IEEE754 规范并编写一些代码,这可能会起作用。
  • 如果您的编译器支持 C++11,您应该使用来自 <cmath>std::isfinite。请参阅cppreference.com 了解更多信息。
  • @paddy 仍然无法解决问题
  • 这只是反对使用二进制数据格式的论据。确定基于轻量级可解析文本的文件格式(如 xml 或 yaml)的有效性要容易得多。
  • _finite() 只是检查 valid 有限值。你的问题比这更难:一个不是 fpu 有效数字的位模式,它(我相信)正在调用一个陷阱处理程序。你可以捕捉到这样的 fpu 陷阱。见msdn.microsoft.com/en-us/library/te2k2f2t.aspx。此外,msdn.microsoft.com/en-us/library/c9676k6h.aspx 用于设置 fpu 模式,包括处理程序调用。

标签: c++ double


【解决方案1】:

我原以为std::isnan 会做你需要做的事情,而且效率最高。如果您在平台上的实现不是这种情况,但假设浮点数使用 IEEE 754 格式时您觉得很舒服,那么您自己编写这些函数并不难。

inline constexpr bool
isnan(const std::uint32_t bits) noexcept
{
  constexpr std::uint32_t exponent = UINT32_C(0x7f800000);
  constexpr std::uint32_t mantissa = UINT32_C(0x007fffff);
  return ((bits & exponent) == exponent) && ((bits & mantissa) != 0);
}

inline constexpr bool
isnan(const std::uint64_t bits) noexcept
{
  constexpr std::uint64_t exponent = UINT64_C(0x7ff0000000000000);
  constexpr std::uint64_t mantissa = UINT64_C(0x000fffffffffffff);
  return ((bits & exponent) == exponent) && ((bits & mantissa) != 0);
}

实现isfinite 更加简单,您只需检查(bits & exponent) != exponent。要实现isnormal,请检查((bits & exponent) != exponent) && ((bits & exponent) != 0))。请注意,根据这个定义,零不是“正常的”。

请注意,函数对整数类型进行操作。这是故意的。您的代码会将 fread 字节转换为整数,您将整数传递给函数以确定它是否表示“非数字”,并且(仅)如果不是,您将 memcpy 字节转换为浮点输入。

【讨论】:

  • 用 IEEE 浮点类型测试 NaN 的另一种方法是 a != a。看起来很傻,但 NaN 值 从不 比较相等。然而,一个过于聪明的编译器可能会优化一个只能有一个结果的测试。在这种情况下,可能需要做一些间接来伪造优化器。
  • @PeteBecker 想法是在将位转换为浮点类型之前测试 NaN,以避免 OP 面临的 FPU 开销。
  • 是的,我在你的回答中忽略了这一点。尽管如此...
猜你喜欢
  • 2010-10-02
  • 1970-01-01
  • 1970-01-01
  • 2015-05-06
  • 1970-01-01
  • 2017-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多