【问题标题】:How to make sure NaNs propagate when using SSE intrinsics?使用 SSE 内在函数时如何确保 NaN 传播?
【发布时间】:2013-03-11 17:35:00
【问题描述】:

我最近读到这篇关于 SSE 算术运算中的 NaN 值的文章:

作用于两个非数字 (NAN) 参数的算术运算的结果未定义。因此,使用 NAN 参数的浮点运算将与相应汇编指令的预期行为不匹配。

来源:http://msdn.microsoft.com/en-us/library/x5c07e2a(v=vs.100).aspx

这是否意味着,例如,添加两个 __m128 值可能会将 NaN 转换为实数?

如果计算依赖于 NaN 值,我也需要最终结果为 NaN。有没有办法做到这一点?

【问题讨论】:

  • @Mysticial:忽略说明不能保证结果的文档是不谨慎的。
  • @EricPostpischil 我不会暗示这里就是这种情况,但之前已知 MSDN 文档有错误。 (因此,我什至对官方文件都持保留态度。)所以我一点也不感到惊讶,写这个 sn-p 的人可能比我们更了解这个话题。跨度>
  • @EricPostpischil 好吧,看看。由于您显然没有其他建设性的内容要说,我将以最后一条评论结束。我不会轻易质疑官方文件。但是当我这样做时,那是因为我有充分的理由这样做。鉴于我对编译器、SSE 内在函数/指令以及它们是如何实现的知识和经验,我可以说这个引用的关于 NaN 的陈述非常牵强(并非不可能,但牵强)。也许它只适用于非常小众的极端案例——他们应该澄清这些,而不是让我们猜测我们大多数人使用的所有“安全”案例
  • @EricPostpischil 当然不能保证结果;您最后一次看到没有提供“没有任何形式的保证”的软件是什么时候?
  • @EricPostpischil 你真的获得了动力,不是吗?你在这次讨论中的反应比你声称的年龄更能说明你的性格。

标签: c++ c floating-point sse nan


【解决方案1】:

当我解释该文本时,它的意思是编译器提供了大致对应于 SSE 指令的各种内在函数。通常,您可以预期编译器将使用 SSE 指令来实现内在函数。但是,这并不严格。内在函数实际上指定了一些抽象计算模型中的操作;他们没有直接指定 SSE 指令。在那个抽象模型中,对两个 NaN 进行操作的结果(奇怪的是它似乎不允许一个 NaN 和一个数字)是未定义的。因此,例如,添加两个 NaN 得到的结果可能不是 NaN。

特别是,抽象模型中的操作将受到编译器优化,并且这些优化可能会导致 SSE 指令以外的其他内容(编译时的计算,如果编译器可以推断出存在 NaN,则省略指令,因此它不会需要实际执行添加等)。

看来,如果你想保证为 SSE 指令指定的语义,你可能不得不用汇编语言编写,而不是在微软的编译器中使用内部函数。

我希望供应商不要再对浮点语义漠不关心了。如果没有明确规定的行为,就很难进行工程设计。

【讨论】:

  • 有一种相对良性的可能性。它可能总是产生一个 NaN,但不一定以任何一致的方式与输入 NaN 相关。如果是这种情况,将其记录在案会很有帮助。
  • 这听起来只有当编译器可以证明两个值是 NaN 并且编译器有充分的理由利用它时才会有问题,恕我直言:前者其中似乎不太可能,后者很难举出一个例子......
  • @PatriciaShanahan:这似乎很有可能。指令返回的两个输入 NaN 中的哪一个通常取决于操作数顺序,并且编译器很可能不会保留从内部函数到指令的顺序。这将导致需要记录返回的两个 NaN 中的哪一个是未定义的,并且对此的草率处理可能会导致文档说明对两个 NaN 进行操作的结果是未定义的。尽管如此,文档说明了它所说的内容。
  • 我觉得奇怪的是,许多语言不允许在没有显式转换的情况下将 double 转换为 float,但会在内部随意将事物提升为 double,然后回退。如果我正在设计一种语言,我将拥有其语义完全符合 IEEE 标准的“IEEE 单”和“IEEE 双”类型,以及具有更有用语义的其他 32 位和 64 位浮点类型(例如,@987654325 @ 在编译的情况下实现等价关系,具有 32 位类型,将使用 64 位中间结果等计算 f1=(f2+f3+f4)`)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-05
  • 1970-01-01
  • 2018-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多