在某些情况下,您知道某个浮点表达式将始终为非负数。例如,计算一个矢量的长度时,一个做sqrt(a[0]*a[0] + ... + a[N-1]*a[N-1])(NB:我是知道的std::hypot,这是不相关的问题),并且平方根下表达显然是非负的。但是,GCC 为以下输出以下程序集sqrt(x*x):
mulss xmm0, xmm0
pxor xmm1, xmm1
ucomiss xmm1, xmm0
ja .L10
sqrtss xmm0, xmm0
ret
.L10:
jmp sqrtf
Run Code Online (Sandbox Code Playgroud)
也就是说,它将结果x*x与零进行比较,如果结果为非负数,则执行sqrtss指令,否则调用sqrtf。
因此,我的问题是:如何强制GCC假定该x*x值始终为非负值,从而跳过比较和sqrtf调用,而无需编写内联汇编?
我想强调的是,我对本地解决方案感兴趣,而不是像-ffast-math,-fno-math-errno或那样做-ffinite-math-only(尽管确实可以解决问题,这要归功于ks1322,harold和Eric Postpischil的评论)。
此外,“强制将GCC假定x*x为非负数”应解释为assert(x*x >= 0.f),因此这也排除了x*xNaN 的情况。
我可以使用特定于编译器,特定于平台,特定于CPU等的解决方案。
我正在设计一个新的微处理器指令集(www.forwardcom.info),我想使用NAN传播来跟踪错误.但是,IEEE 754浮点标准中有许多奇怪的事情可以防止这种情况发生.
首先,我想使用NAN传播而不是错误捕获的原因是我有可变长度的向量寄存器.例如,如果我有一个带有8个元素的浮点向量,并且我在第一个元素中有1/0而在第六个元素中有0/0,那么我只得到一个陷阱,但如果我在计算机上运行相同的程序矢量长度的一半然后我得到两个陷阱:一个用于无穷大,一个用于NAN.我希望结果与向量长度无关,所以我需要依赖于NAN和INF的传播而不是陷阱.NAN和INF值将通过计算传播,以便在最终结果中检查它们.NAN表示包含一些称为有效负载的位,可用于有关错误源的信息.
但是,IEEE 754浮点标准中存在两个阻止NAN值可靠传播的问题.
第一个问题是具有不同有效载荷的两个NAN的组合只是两个值中的一个.例如,NAN1 + NAN2给出NAN1.这违反了a + b = b + a的基本原则.编译器可以交换操作数,以便在不同的编译器或不同的优化选项上获得不同的结果.我更喜欢得到两个有效载荷的按位OR组合.如果每个错误条件都有一位,那么这将起作用,但当然,如果有效负载包含更复杂的信息(例如具有动态类型的语言中的NAN装箱),则无效.标准委员会实际讨论了OR'ing解决方案(参见http://grouper.ieee.org/groups/754/email/msg01094.html).我不知道他们为什么拒绝这个提议.
第二个问题是如果只有一个输入是NAN,则min和max函数不传播NAN.换句话说,min(1,NAN)= 1.可靠的NAN传播当然需要min(1,NAN)= NAN.我不知道为什么标准会说这个.
在名为ForwardCom的新微处理器系统中,我想避免这些不幸的怪癖并指定NAN1 + NAN2 = NAN1 | NAN2和min(1,NAN)= NAN.
现在我的问题是:首先,我是否需要一个选项切换来在严格的IEEE一致性和可靠的NAN传播之间进行切换?引用标准:
安静的NaN应该由实施者自行决定提供从无效或不可用的数据和结果中继承的回顾性诊断信息.为了便于传播NaN中包含的诊断信息,应尽可能多地保留NaN操作结果中的信息.
注意标准在这里说"应该",在其他地方有"应该".这是否意味着我允许偏离建议?
第二个问题:我找不到任何实际使用NAN传播来跟踪错误的例子.也许这是因为标准的弱点.我想为不同的错误条件定义不同的有效负载位,例如:
0/0,0*∞,∞/∞,模(1,0),模(∞,1),∞-∞,以及涉及无穷大和除零的其他误差.
sqrt(-1),log(-1),pow(-1,0.1)以及从对数和幂导出的其他错误.
asin(2)和其他数学函数.
明确的分配.当变量初始化为NAN时,这可能很有用.
用户定义的错误代码有很多空位.
这是否已经完成,或者我是否必须从零开始创造一切?我有什么问题需要考虑(除了某些语言的NAN拳击)
引用(感谢作者开发和共享算法!):
https://tavianator.com/fast-branchless-raybounding-box-intersections/
由于现代浮点指令集可以在没有分支的情况下计算最小值和最大值
作者的相应代码就是
dmnsn_min(double a, double b)
{
return a < b ? a : b;
}
Run Code Online (Sandbox Code Playgroud)
我很熟悉例如_mm_max_ps,但这是一个矢量指令.上面的代码显然是用于标量形式.
题:
以防万一:我熟悉在C++中使用min和max函数,相信它是相关的,但不是我的问题.