两个数的乘法是一个恒定时间算法吗?

时间:2013-07-28 14:42:59

标签: c++ operators

假设我写,

int a = 111;
int b = 509;
int c = a * b;

那么计算'a * b'的时间复杂度是多少?如何执行乘法运算?

5 个答案:

答案 0 :(得分:11)

编译此功能:

int f(int a, int b) {
    return a * b;
}

使用gcc -O3 -march=native -m64 -fomit-frame-pointer -S为我提供以下程序集:

f:
    movl    %ecx, %eax
    imull   %edx, %eax
    ret

第一条指令(movl)加载第一个参数,第二条指令(imull)加载第二个参数并将其与第一个参数相乘 - 然后返回结果。

实际的乘法是用imull完成的,根据您的CPU类型,它将占用一定的CPU周期。

如果查看Agner Fog's instruction timing tables,您可以看到每条指令需要多长时间。在大多数x86处理器上,它似乎是一个小常量,但AMD K8上带有64位参数的imul指令和结果显示为4-5 CPU周期。我不知道这是一个测量问题还是真正可变的时间。

另请注意,除了执行时间外,还涉及其他因素。整数必须通过处理器移动并进入正确的位置才能成倍增加。所有这些因素和其他因素都会导致延迟,这在Agner Fog的表格中也有所体现。还有其他问题,例如缓存问题也会让生活变得更加困难 - 简单地说一下如果没有运行它会有多快运行并不容易。


x86并不是唯一的体系结构,实际上并不是不可思议的,那里有CPU和体系结构具有非恒定的时间乘法。这对于使用乘法的算法可能容易受到这些平台上的定时攻击的加密技术尤为重要。

答案 1 :(得分:2)

在大多数常见架构上的乘法本身将是不变的。加载寄存器的时间可能会根据变量的位置(L1,L2,RAM等)而有所不同,但操作所需的周期数将保持不变。这与sqrt之类的操作形成对比,这些操作可能需要额外的周期才能达到一定的精度。

你可以在这里获得AMD,英特尔和威盛的指导成本:http://www.agner.org/optimize/instruction_tables.pdf

答案 2 :(得分:1)

按时间复杂度,我认为你的意思是它是否取决于a和b中的位数?那么CPU时钟周期的数量是否会根据您是否乘以2 * 3或111 * 509而变化。我认为是的,它们会有所不同,这将取决于该架构如何实现乘法运算以及如何存储中间结果。 虽然可以有很多方法可以做到这一点,但一种简单/原始的方法是使用binary adder/subtractor电路实现乘法。 a * b的乘法是使用n位二进制加法器向自身添加b次。类似地,除法a / b是从a减去b直到它达到0,尽管这将需要更多的空间来存储商和余数。

答案 3 :(得分:0)

void myfun()
{
int a = 111;
int b = 509;
int c = a * b;
}

组装部分:

movl    $111, -4(%ebp)
movl    $509, -8(%ebp)
movl    -4(%ebp), %eax
imull   -8(%ebp), %eax

因此,您可以看到它全部取决于imull指令,特别是CPU的获取,解码和执行周期。

答案 4 :(得分:0)

在您的示例中,编译器将进行乘法运算,您的代码看起来像

int c = 56499;

如果您将示例更改为

int c = a * 509;

然后编译器MIGHT决定重写你的代码,如

int c = a * ( 512 - 2 - 1 );
int c = (a << 9) - (a << 1) - a;

我说可能因为编译器会将使用衬衫的成本与乘法指令的成本进行比较并选择最佳选项。 给定快速多指令,通常意味着只有1或2个移位会更快。

如果您的数字太大而无法输入整数(32位),那么任意精度 数学例程在O(n ^ 2)和O(n log n)时间之间使用,其中n是保存数字所需的32位部分的数量。