让我们说我们有这些不平等:
if (a*a+b*b>0) {
...
}
if (a*b+c*d>0) {
...
}
显然,它们都需要2次乘法来评估
问题是,我们真的需要计算2个全精度产品才能检查这些表达是否为正?
是否有任何数学技巧可以让我在不需要评估2个产品的情况下编写命令?
它会更快吗?
或者编译器可能会尽可能快地完成它?
我是否在思考?
编辑: 嗯,这很快就升级了。 我只是想指出一般的说法。无论如何,我在任何项目中都不需要这样的微优化。 还有,是的,我可以省略第一个因为太琐碎。可能第二个更有趣。
答案 0 :(得分:2)
你的“我是否过度思考”这个问题告诉我,你没有通过真正分析代码来发现这是一个真正的瓶颈。所以我会说是的,你只是想做一个过早的优化。
然而,如果这确实是您的应用程序的主要性能关键部分,那么我现在能想到的唯一改进如下。由于实数的平方永远不会是负数,因此“平方大于零”等同于“a不为零”。因此,如果您的架构上的比较很快(嗯,那是相对的 - 比乘法更快),那么
if (a*a+b*b>0) {
...
}
可以写成
if (a || b) {
...
}
(假设没有出现转角情况。如果变量是有符号整数或表示实数的浮点数,那么这应该没问题。但是,如果有一些无符号整数溢出或涉及复数,那么你将必须执行额外的检查,此时,如果没有真正的分析,很难推断相对性能。)
对于我脑海中的第二个案例,我没有这样一个“聪明”的“优化”,但也许其他人可以提出类似的东西 - 当且仅当它是绝对必要的。 否则 - 当性能不重要时,代码可读性优于性能。
答案 1 :(得分:1)
我假设这些表达式都不会溢出,因为类型没有溢出的概念或因为值在范围内。当溢出和潜在的环绕进入图片时(例如,如果a
和b
是unsigned int
),则适用不同的规则。
第一个陈述显然等同于
if (a != 0 || b != 0)
或
if (a || b)
交换额外的分支进行两次乘法和加法。
第二个陈述更有趣:我认为确定操作数的符号是合理的,只有当a*b
和c*d
具有相反符号时才进行实际数学运算。在所有其他情况下,可以在不知道实际值的情况下确定条件。结果逻辑是否比计算更快将取决于类型,我猜。
答案 2 :(得分:1)
第一个将始终为> = 0.当且且仅当a
和b
为0时,它将为0,因此它等同于:
if (a || b) {
...
}
关于第二个问题:如果a
的符号等于b
的符号,并且c
的符号等于d
的符号,那么它就是&#39 ;与上述情况相同:
if (sign(a)==sign(b) && sign(c)==sign(d))
{
if ((a && b) || (c && d))
{
... > 0
}
else
{
... = 0
}
}
else
{
if (sign(a)*sign(b)==sign(c)*sign(d))
{
... <= 0
}
else
{
/* must do the actual product to find out */
}
}
对于符合IEEE-754标准的浮点数,符号位于每个数字的MSb处。
对于模拟FP的环境,您可以做一件事来优化比较:如果您只是比较产品的两个结果,您可以避免添加:
if (a*b>c*d) {
...
}
这有点快,因为要比较两个浮点数,你只需比较它们就像它们是有符号整数一样,而无FP的CPU肯定会有资源来比它花费的时间更快地比较两个整数FP软件的补充。
答案 3 :(得分:0)
另一个重写(假设您正在使用浮点数,它们符合32 bits wide and IEEE 754,并且与int的大小相同;是的,这是hacky和平台相关的)。
对于第一种情况,您可以使用单个按位'或'&amp; '和'(用于忽略符号位和指数,仅保留尾数;如果不能有任何-0,则可以删除它):
if (*((int *)&a) | (*(int *)&b) & 0x7FFFFF) { // a*a + b*b>0
...
}
我真的怀疑第二种情况下没有任何类似的无分支魔法。