有原始按照每次项相乘的方式来计算和使用horner方法进行多项式求和运算;
- 使用原始计算方法,代码如下:
double poly_original(double *a, double x, long degree) { long i; double result = a[0]; double xpwr = x; for(i = 1; i <= degree; i++ ) { result += a[i] * xpwr; xpwr = x * xpwr; }
return result; } |
- 使用horner 方法计算方法和代码如下:
公式为:
代码如下:
double poly_horner(double *a, double x, long degree) { long i; double result = a[degree]; for(i = degree - 1; i >= 0; i-- ) { result = a[i] + x * result; }
return result; } |
比较这两个方法的性能,我们直觉上会发现,原始的方法的乘法运算的数量是第二种方法的两倍,因此,按理说,第一种方法应该要慢很多才对,实际上,第一种方法运行的速度还是要快一些。
它们的objdump汇编代码如下:黄色是每次循环运行的代码
原始计算方法:
000000000040077d <_Z13poly_originalPddl>: 40077d: f2 0f 10 17 movsd (%rdi),%xmm2 400781: 48 85 f6 test %rsi,%rsi 400784: 7e 23 jle 4007a9 <_Z13poly_originalPddl+0x2c> 400786: 66 0f 28 c8 movapd %xmm0,%xmm1 40078a: b8 01 00 00 00 mov $0x1,%eax 40078f: 66 0f 28 d9 movapd %xmm1,%xmm3 400793: f2 0f 59 1c c7 mulsd (%rdi,%rax,8),%xmm3 400798: f2 0f 58 d3 addsd %xmm3,%xmm2 40079c: f2 0f 59 c8 mulsd %xmm0,%xmm1 4007a0: 48 83 c0 01 add $0x1,%rax 4007a4: 48 39 c6 cmp %rax,%rsi 4007a7: 7d e6 jge 40078f <_Z13poly_originalPddl+0x12> 4007a9: 66 0f 28 c2 movapd %xmm2,%xmm0 4007ad: c3 retq |
从上面的代码分析,关键数据路径是mulsd (%rdi,%rax,8),%xmm3和addsd %xmm3,%xmm2,而mulsd %xmm0,%xmm1、add $0x1,%rax,cmp %rax,%rsi, movapd %xmm1,%xmm3,都可以在它运行的期间完成。
Horner方法:
00000000004007ae <_Z11poly_hornerPddl>: 4007ae: f2 0f 10 0c f7 movsd (%rdi,%rsi,8),%xmm1 4007b3: 48 83 ee 01 sub $0x1,%rsi 4007b7: 78 13 js 4007cc <_Z11poly_hornerPddl+0x1e> 4007b9: f2 0f 59 c8 mulsd %xmm0,%xmm1 4007bd: f2 0f 58 0c f7 addsd (%rdi,%rsi,8),%xmm1 4007c2: 48 83 ee 01 sub $0x1,%rsi 4007c6: 48 83 fe ff cmp $0xffffffffffffffff,%rsi 4007ca: 75 ed jne 4007b9 <_Z11poly_hornerPddl+0xb> 4007cc: 66 0f 28 c1 movapd %xmm1,%xmm0 4007d0: c3 retq |
从上面的代码分析,关键数据路径是mulsd %xmm0,%xmm1和addsd (%rdi,%rsi,8),%xmm1。
因此,从上面看,它们的性能应该是等同的才对。
下面是我的测量数据:
root@opzoon-All-Series:/data_1/songqing/for_test/keyDataPath# ./a.out
keyDataPath.cpp(66): original cost 25776997 microsecond
keyDataPath.cpp(76): horner cost 27069789 microsecond
root@opzoon-All-Series:/data_1/songqing/for_test/keyDataPath# ./a.out
keyDataPath.cpp(66): original cost 25915710 microsecond
keyDataPath.cpp(76): horner cost 26932413 microsecond
root@opzoon-All-Series:/data_1/songqing/for_test/keyDataPath# ./a.out
keyDataPath.cpp(66): original cost 25804754 microsecond
keyDataPath.cpp(76): horner cost 27919597 microsecond
但是,为什么原始方法会稍微快一点呢???