C语言内嵌汇编灵异事件:多了一段语句却执行得更快了,为什么?

只是在尝试着做一个开方函数,然后灵异事件就出现了

首先写了一个InvSqrt(x)(求x^-(1/2)),
测试结果无误后复制了其代码,在末尾加上"结果*x"再返回,封装为fsqrt(x)函数
灵异现象出现了:fsqrt(x)跑得比InvSqrt(x)还快!这是为什么?

sqrt.h:
#ifndef sqrt_h
#define sqrt_h 1

__fastcall float fsqrt(float s);
__fastcall float InvSqrt(float s);
asm(
"fsqrt:;"
    "movd %xmm0,%eax;"
    "mov %eax,%edx;"
    "not %eax;"
    "add $0xbe6f02e3,%eax;"//or maby 0xbe6f02e2
    "shr %eax;"
    "movd %eax,%xmm0;"//guessnum
    "add $0x7f800000,%edx;"
    "movd %edx,%xmm2;"//-s/2
    "mov $0x3fc00000,%eax;"
    "movd %eax,%xmm3;"//1.5
    "movss %xmm0,%xmm1;"
    "mulss %xmm0,%xmm0;"
    "mulss %xmm2,%xmm0;"
    "addss %xmm3,%xmm0;"
    "mulss %xmm1,%xmm0;"
    "movss %xmm0,%xmm1;"
    "mulss %xmm0,%xmm0;"
    "mulss %xmm2,%xmm0;"
    "addss %xmm3,%xmm0;"
    "mulss %xmm1,%xmm0;"
    "movss %xmm0,%xmm1;"
    "mulss %xmm0,%xmm0;"
    "mulss %xmm2,%xmm0;"
    "addss %xmm3,%xmm0;"
    "mulss %xmm1,%xmm0;"
    "add $0x80800000,%edx;"
    "movd %edx,%xmm1;"
    "mulss %xmm1,%xmm0;"
    "ret;"
);
asm(
"InvSqrt:"
    "movd %xmm0,%eax;"
    "mov %eax,%edx;"
    "not %eax;"
    "add $0xbe6f02e3,%eax;"//or maby 0xbe6f02e2
    "shr %eax;"
    "movd %eax,%xmm0;"//guessnum
    "add $0x7f800000,%edx;"
    "movd %edx,%xmm2;"//-s/2
    "mov $0x3fc00000,%eax;"
    "movd %eax,%xmm3;"//1.5
    "movss %xmm0,%xmm1;"
    "mulss %xmm0,%xmm0;"
    "mulss %xmm2,%xmm0;"
    "addss %xmm3,%xmm0;"
    "mulss %xmm1,%xmm0;"
    "movss %xmm0,%xmm1;"
    "mulss %xmm0,%xmm0;"
    "mulss %xmm2,%xmm0;"
    "addss %xmm3,%xmm0;"
    "mulss %xmm1,%xmm0;"
    "movss %xmm0,%xmm1;"
    "mulss %xmm0,%xmm0;"
    "mulss %xmm2,%xmm0;"
    "addss %xmm3,%xmm0;"
    "mulss %xmm1,%xmm0;"
    "ret;"
);

#endif
sqrt.c
#include <stdio.h>
#include <time.h>
#include <conio.h>
#include <math.h>
#include "sqrt.h"

int main()
{
    register int a,n=100000000;
    int t;
again:
    //下面的部分进行速度测试 
    printf("speed tests:\n");
    
    t=clock();
    for(a=0;a<n;++a) InvSqrt(a);
    printf("%lf\n",(double)(clock()-t)/CLOCKS_PER_SEC);
    
    t=clock();
    for(a=0;a<n;++a) fsqrt(a);
    printf("%lf\n",(double)(clock()-t)/CLOCKS_PER_SEC);
    
    t=clock();
    for(a=0;a<n;++a) sqrtf(a);
    printf("%lf\n",(double)(clock()-t)/CLOCKS_PER_SEC);
    
    t=clock();
    for(a=0;a<n;++a) sqrt(a);
    printf("%lf\n",(double)(clock()-t)/CLOCKS_PER_SEC);
    
    t=clock();
    for(a=0;a<n;++a) sqrtl(a);
    printf("%lf\n",(double)(clock()-t)/CLOCKS_PER_SEC);
    
    system("pause");
    goto again;//再测试一遍 
    return 0;
}
测试机子:

CPU: Intel(R) Pentium(R) CPU G630 @2.7GHz
GPU: Intel(R) HD Graphics
用的是Dev-C++
系统是WIN10

运行结果:
speed tests:
1.390000
0.902000
1.418000
1.520000
1.761000
请按任意键继续. . .
speed tests:
1.154000
0.975000
1.168000
1.092000
1.720000
请按任意键继续. . .
speed tests:
1.156000
0.909000
1.188000
1.233000
1.641000
请按任意键继续. . .
speed tests:
1.221000
0.877000
1.135000
1.221000
1.653000
请按任意键继续. . .

就是这样,无论测试多少遍都是fsqrt比InvSqrt快!

为什么呢?

我有试过,交换两个汇编代码块的位置,交换两个测试代码的位置,也都是fsqrt比InvSqrt快。
为什么呢?
还有我发现如果把fsqrt最末尾的两个xmm1改为xmm2,速度会降很多。
为什么呢?
以及,这个代码好像只能用64位编译器(TDM-GCC 4.9.2 64-bit Release/Debug/Profiling)编译,我这里面的其他编译器都不会通过。

希望能了解这里面的原因,以后能利用这些原理预测代码的执行效率。

无profiler不要谈效率!!尤其在这个云计算、虚拟机、模拟器、CUDA、多核 、多级cache、指令流水线、多种存储介质、……满天飞的时代!

img