浮点数乘法和加法效率有多大差别?
最近遇到一个问题,希望提高我的一个程序的效率,它里面有一个很大的循环,循环体内又有比较多的浮点(double)乘法、加法以及幂运算,执行速度很不怎么样。我以为是幂运算的原因,于是想把它化成查表或者什么的办法,给效率优化下。
接着我做了个测试,得到一个很悲剧的结果。。。
是这样的,我做了10亿次循环,里面分别填入求幂、乘法、加法(double)、加法(int),结果发现除了Debug版本求幂执行时间明显超过其他外,其余运算时间差异太小,release下更是接近。
有人给我解释一下吗?谢谢
代码:
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <cstring>
#include <cstdio>
int main(int argc, char* argv[])
{
int m = 28;
int n = 28;
clock_t start, end;
const int counts = 100000000;
start = clock();
for (long long i=0; i<counts; ++i)
{
double xx = pow(1.9, -3.3);
}
end = clock();
printf_s("Time: %f", (double)(end - start)/CLOCKS_PER_SEC);
start = clock();
for (long long i=0; i<counts; ++i)
{
double xx = 3.3*1.9;
}
end = clock();
printf_s("Time: %f", (double)(end - start)/CLOCKS_PER_SEC);
double table[100];
memset(table, 0, 100*sizeof(double));
start = clock();
for (long long i=0; i<counts; ++i)
{
double xx = table[10];
}
end = clock();
printf_s("Time: %f", (double)(end - start)/CLOCKS_PER_SEC);
start = clock();
for (long long i=0; i<counts; ++i)
{
double xx = 1.3+3.1;
}
end = clock();
printf_s("Time: %f", (double)(end - start)/CLOCKS_PER_SEC);
start = clock();
for (long long i=0; i<counts; ++i)
{
int x = 18+21;
}
end = clock();
printf_s("Time: %f", (double)(end - start)/CLOCKS_PER_SEC);
system("pause");
return 0;
}
Debug:Time: 5.708000 Time: 0.345000 Time: 0.344000 Time: 0.346000 Time: 0.311000
Release:Time: 0.140000Time: 0.113000Time: 0.112000Time: 0.111000Time: 0.108000
[解决办法]
最后都用release,Debug是用于调试的
[解决办法]
加法和乘法现在都是单指令周期的计算,因此一样快
[解决办法]
我把楼主的代码改了一下,用gcc编译,去掉所有优化,我感概的是,gcc标准库函数pow的设计者所设计的算法令人惊叹,与输入规模基本无关,即算法的效率是常数级!
我计算一亿次pow( 20, 50 )与一亿次pow( 20, 100 ),后者的输入规模是前者的一倍,但执行时间居然是一样的!
可见,pow使用的算法并非简单地将幂化为乘法,即不是50个20相乘或者100个20相乘。
[解决办法]
Release版本下的常量加减乘除应该被优化成常数了吧
[解决办法]
这个代码应该会被编译期展开吧?
[解决办法]
主要指令的执行时间在intel文档里都是可以查到的。
[解决办法]
浮点数的 pow( a , b ) 一般都是化成 exp( log(a) * b ) 计算..
整数的 pow( a , b ) 一般都是快速幂运算( b 分奇数偶数这样子化简, pow( a , 2*N) == pow( a * a , N ) , pow( a , 2*N+1) == a * pow( a * a , N ) ), 复杂度 O(log(N))..
x86 下的pow应该直接掉fpu的...