5

哪个版本更快? x * 0.5 or x / 2

前段时间,我在大学里有一门叫做计算机系统的课程。从那时起,我记得可以通过比较“简单”的逻辑门来实现两个值相乘,但除法不是“本机”操作,并且需要一个循环中的求和寄存器,该求和寄存器由除数增加并与被除数相比。

现在我必须优化一个有很多部门的算法。不幸的是,它不只是除以二,所以二进制移位是没有选择的。将所有除法更改为乘法会有所不同吗?

更新:

我已经更改了我的代码,并没有发现任何区别。您可能对编译器优化是正确的。因为所有的答案都很棒,所以我都投了赞成票。我选择了 rahul 的答案,因为链接很好。

4

5 回答 5

10

通常除法比乘法昂贵得多,但是智能编译器通常会将除法转换为编译时常量的乘法。如果您的编译器不够智能,或者存在浮点精度问题,那么您始终可以显式进行优化,例如更改:

 float x = y / 2.5f;

到:

 const float k = 1.0f / 2.5f;

 ...

 float x = y * k;

请注意,这很可能是过早优化的情况- 如果您已对代码进行了概要分析,并且明确地将除法确定为性能瓶颈,您应该只做这种事情。

于 2012-10-19T15:06:21.813 回答
7

对于整数和浮点数(它基本上可以转换为位移),除以 2 的幂的编译时常数非常快(与乘以编译时常数相当)。

对于浮点数,即使是动态除以 2 的幂也比常规(动态或静态除法)快得多,因为它基本上变成了指数的减法。

在所有其他情况下,除法似乎比乘法慢几倍。

对于动态除数,我的Intel(R) Core(TM) i5 CPU M 430 @ 2.27GHz的减速因子似乎约为 8,静态因子约为 2。

结果来自我的一个小基准,我之所以做出这个基准,是因为我对此有点好奇(注意二次方的畸变):

在此处输入图像描述

在此处输入图像描述

  • ulong -- 64 位无符号
  • 标签中的 1 表示动态参数
  • 标签中的 0 表示静态已知参数

结果是从以下 bash 模板生成的:

#include <stdio.h>
#include <stdlib.h>
typedef unsigned long ulong;
int main(int argc, char** argv){
    $TYPE arg = atoi(argv[1]);
    $TYPE i = 0, res = 0;
    for (i=0;i< $IT;i++)
        res+=i $OP $ARG;
    printf($FMT, res);
    return 0;
}

分配 $-variables 并编译-O3并运行生成的程序(动态值来自命令行,因为从 C 代码中很明显)。

于 2016-08-09T18:04:23.977 回答
4

这可能取决于您的特定 CPU 和参数的类型。例如,在您的示例中,您正在执行浮点乘法但整数除法。(可能,至少,在我所知道的大多数语言中,它使用 C 语法。)

如果您在汇编程序中工作,您可以查看您正在使用的特定指令并查看它们需要多长时间。

如果您不是在汇编程序中工作,您可能不需要关心。所有具有优化功能的现代编译器都会以这种方式将您的操作更改为最合适的指令。

您在优化方面的巨大胜利不会来自像这样玩弄算术。相反,请关注您使用缓存的情况。考虑是否有可能加快速度的算法更改。

于 2012-10-19T15:09:15.567 回答
4

好吧,如果它是一个单一的计算,你几乎不会注意到任何区别,但如果你谈论数百万笔交易,那么除法肯定比乘法更昂贵。您始终可以使用最清晰易读的任何内容。

请参考此链接:-我应该使用乘法还是除法?

于 2012-10-19T15:12:11.530 回答
0

如果您正在寻找数值稳定性,请注意:

不要为需要多个分量/坐标的解决方案回收除法,例如实现 nD 向量 normalize() 函数,即以下内容不会为您提供单位长度向量:

V3d v3d(x,y,z);
float l = v3d.length();
float oneOverL = 1.f / l;
v3d.x *= oneOverL;
v3d.y *= oneOverL;
v3d.z *= oneOverL;
assert(1. == v3d.length()); // fails!

..但是这段代码会..

V3d v3d(x,y,z);
float l = v3d.length();
v3d.x /= l;
v3d.y /= l;
v3d.z /= l;
assert(1. == v3d.length()); // ok!

猜想第一个代码摘录中的问题是额外的浮点归一化(预除法将对浮点数施加不同的比例归一化,然后强制实际结果并引入额外的错误)。

没有研究太久,所以请分享您的解释为什么会发生这种情况。用 x,y 和 z 为 .1f 进行了测试(并且使用双精度数而不是浮点数)

于 2022-02-25T09:52:37.460 回答