如果喜欢使用-ffast-math,那么double的好哨兵值

问题描述 投票:10回答:1

由于gcc选项-ffast-math有效地禁用了NaN-/+inf,我正在寻找可能是我的性能关键数学代码中代表NaN的下一个最佳选择。理想情况下,如果对(add,mul,div,sub等)进行操作的前哨值将产生NaN会做的哨兵值,但我怀疑这是可能的,因为我认为NaN是唯一能够实现这一点的值。 -0.0可能不太适合,因为它在-ffast-math也被禁用,可能会阻止某些优化,如(x+0.0)等。

也许我的问题应该是,有没有办法使用NaN或其他一些“特殊的双重”,同时能够启用大量的数学优化而不会崩溃?

系统是Linux/x64, gcc 4.8.1

c optimization double nan fast-math
1个回答
4
投票

如果您正在寻找一个可以通过算术运算传播的值,NaN仍然可以选择-ffast-math。问题出在其他地方。使用-ffast-math,由于优化,一些操作可以从计算中移除,然后无法保证NaN或任何其他值将被传播。

例如,以下,使用-ffast-math设置,将导致硬编写0.0n并且n没有特殊的价值可以保护它。

float n = NAN;
n *= 0.0;

你可以做的一件事就是使用-fno-finite-math-only -ftrapping-math-ffast-math,Shafik Yaghmour说。另一方面,如果只有少数几个地方你期望一个不好的价值,你可以自己检查它,把测试完全放在那些点上。

我能想到的最后一个选项 - 如果你真的非常需要优化 - 是手动将NaN(可能是inf)值注入计算并检查它传播的时间。然后在那些传播停止的地方,测试NaNinf)的发生。 - 这是一种不安全的方法,因为我不是百分百肯定,-ffast-math可以涉及有条件的操作流程。如果可以的话,这个解决方案很有可能无效。所以它有风险,如果选择需要非常繁重的测试,涵盖计算的所有分支。

通常我会反对最后的解决方案,但实际上有机会,NaNinf)值将通过整个计算或几乎整体传播,因此它可以提供您正在寻求的性能。所以你可能想承担风险。


正如Shafik Yaghmour所说,用NaN检查-ffast-math你能做什么

inline int isnan(float f)
{
    union { float f; uint32_t x; } u = { f };
    return (u.x << 1) > 0xff000000u;
}

double

inline int isnan(double d)
{
    union { double d; uint64_t x; } u = { d };
    return (u.x << 1) > 0xff70000000000000ull;
}

检查inf将是

inline int isinf(float f)
{
    union { float f; uint32_t x; } u = { f };
    return (u.x << 1) == 0xff000000u;
}

inline int isinf(double d)
{
    union { double d; uint64_t x; } u = { d };
    return (u.x << 1) == 0xff70000000000000ull;
}

你也可以合并isnanisinf

© www.soinside.com 2019 - 2024. All rights reserved.