10

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

也许我的问题应该是,有什么方法可以使用NaN或其他一些“特殊的双倍”,同时能够在不崩溃的情况下启用很多数学优化?

系统是Linux/x64, gcc 4.8.1

4

1 回答 1

4

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

例如,带有-ffast-mathset 的以下内容将导致硬写入0.0n并且没有n可以保护它的特殊值。

float n = NAN;
n *= 0.0;

您可以做的一件事就是使用-fno-finite-math-only -ftrapping-mathwith ,-ffast-math就像 Shafik Yaghmour 所说的那样。另一个是,如果只有少数地方你期望一个坏的值,你可以自己检查它,在这些点上进行测试。

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

通常我宁愿反对最后一个解决方案,但实际上有机会,NaN( inf) 值将通过整个计算或几乎整个传播,因此它可以提供您所寻求的性能。所以你可能想冒险。


正如 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

于 2013-09-07T11:56:36.120 回答