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

时间:2021-04-16 09:10:54

Since the gcc option -ffast-math effectively disables NaN and -/+inf, I'm looking for maybe the next best option for representing NaN in my performance-critical math code. Ideally the sentinel value if operated on (add, mul, div, sub, etc..) would yield the sentinel value as NaN would do but I doubt this would be possible since I think NaN is the only value that accomplishes this. -0.0 might not be a good fit as it's also disabled in -ffast-math and could prevent certain optimizations like (x+0.0), etc..

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

Perhaps my question should rather be, is there any way to use NaN or some other "special double" while being able to enable a lot of the math optimizations without breaking down?

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

System is Linux/x64, gcc 4.8.1.

系统是Linux / x64,gcc 4.8.1。

1 个解决方案

#1


4  

If you are looking for a value which would be propagated by arithmetic operations, NaN is still available with option -ffast-math. The problem lies somewhere else. With -ffast-math some operations can removed from the computation due to optimization, and then there is no way to guarantee NaN or any other value would be propagates.

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

For example, the following, with -ffast-math set, will cause hard writing 0.0 into n and there is no special value for n which would protect from it.

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

float n = NAN;
n *= 0.0;

One thing you can do, is to use -fno-finite-math-only -ftrapping-math with -ffast-math as Shafik Yaghmour said. And the other is, if there are only few places where you expect a bad value, you can check for it by yourself putting tests exactly in those points.

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

The last option I can think -- if you really badly need optimization -- is to manually inject NaN (and maybe inf) values into the computation and check for how long it is propagated. Then in those places where the propagation stops, test for NaN (inf) occurrence. -- This is an unsafe method, as I am not one hundred percent sure, can -ffast-math involve conditional flow of operations. If it can, there is a significant chance, this solution will be invalid. So it is risky and if chosen needs very heavy testing covering all branches of the computation.

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

Normally I would be rather against the last solution, but actually there is a chance, NaN (inf) values will be propagated though the whole computation or almost whole, so it can give the performance you are seeking for. So you may want to take the risk.

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


Checking for NaN with -ffast-math you can do, as Shafik Yaghmour said, with

正如Shafik Yaghmour所说,你可以用-ffast-math检查NaN

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

and for double with

和双倍的

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

Checking for inf would be

检查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;
}

You can also merge isnan and isinf.

你也可以合并isnan和isinf。

#1


4  

If you are looking for a value which would be propagated by arithmetic operations, NaN is still available with option -ffast-math. The problem lies somewhere else. With -ffast-math some operations can removed from the computation due to optimization, and then there is no way to guarantee NaN or any other value would be propagates.

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

For example, the following, with -ffast-math set, will cause hard writing 0.0 into n and there is no special value for n which would protect from it.

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

float n = NAN;
n *= 0.0;

One thing you can do, is to use -fno-finite-math-only -ftrapping-math with -ffast-math as Shafik Yaghmour said. And the other is, if there are only few places where you expect a bad value, you can check for it by yourself putting tests exactly in those points.

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

The last option I can think -- if you really badly need optimization -- is to manually inject NaN (and maybe inf) values into the computation and check for how long it is propagated. Then in those places where the propagation stops, test for NaN (inf) occurrence. -- This is an unsafe method, as I am not one hundred percent sure, can -ffast-math involve conditional flow of operations. If it can, there is a significant chance, this solution will be invalid. So it is risky and if chosen needs very heavy testing covering all branches of the computation.

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

Normally I would be rather against the last solution, but actually there is a chance, NaN (inf) values will be propagated though the whole computation or almost whole, so it can give the performance you are seeking for. So you may want to take the risk.

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


Checking for NaN with -ffast-math you can do, as Shafik Yaghmour said, with

正如Shafik Yaghmour所说,你可以用-ffast-math检查NaN

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

and for double with

和双倍的

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

Checking for inf would be

检查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;
}

You can also merge isnan and isinf.

你也可以合并isnan和isinf。