无心人 发表于 2009-2-18 07:53:30


__declspec(naked)
DWORD __fastcall iSqrt_FPU1_yaos(DWORD n)
{
__asm
{
   push ecx
   sub esp, 4
   mov word ptr , 0x0E60
   fnstcw word ptr
   mov eax, ecx
   shr eax, 31
   fld qword ptr
   fild dword ptr
   faddp st(1), st
   fsqrt
   fldcw word ptr
   fistp dword ptr
   fldcw word ptr
   mov eax,
   add esp, 8
   ret
   }
}
再次优化99#代码

无心人 发表于 2009-2-18 08:51:25

:)
宝宝的FPU3版本可修改为
__declspec(naked)
DWORD __fastcall iSqrt_FPU3_lbc(DWORD n)
{
__asm
{
push ecx
shr ecx, 31
fld qword ptr
fild dword ptr
faddpst(1),st
fsqrt

//设置FPU的取整方式为了直接使用fistp浮点指令
FNSTCW            // 保存协处理器控制字,用来恢复
mov word ptr , 0x0E60   //截断, 64位浮点
FWAIT
FLDCW               // 载入协处理器控制字,RC场已经修改

fistp   dword ptr

//恢复FPU的取整方式
FWAIT
FLDCW   

pop eax
ret
}
}比较了SSE3版本,和宝宝的版本2几乎相同
另外,在我的机器上,我的FPU几个版本和宝宝的差距很小
测试的0-2^24-1
iSqt_FPU1_lbc#: 0.60082 s
iSqt_FPU2_lbc#: 0.60123 s
iSqt_FPU3_lbc#: 0.60077 s    //修改为上面版本
iSqt_FPU_yaos#: 0.62264 s
iSqt_FPU1_yaos#: 0.60129 s//修改为SSE3版本
iSqt_FPU2_yaos#: 0.60084 s

无心人 发表于 2009-2-18 08:55:36

iSqt_FPU1_lbc#: 0.60160 s
iSqt_FPU2_lbc#: 0.60122 s
iSqt_FPU3_lbc#: 0.60101 s
iSqt_FPU_yaos#: 0.60096 s//修改为101#版本
iSqt_FPU1_yaos#: 0.60080 s //修改为SSE3版本
iSqt_FPU2_yaos#: 0.60056 s

无心人 发表于 2009-2-18 09:06:21


__declspec(naked)
DWORD __fastcall iSqrt_FPU3_lbc(DWORD n)
{
        __asm
        {
                push ecx
                shr ecx, 31
                fld qword ptr
                fild dword ptr
                faddpst(1),st
                fsqrt
                       
                //设置FPU的取整方式为了直接使用fistp浮点指令
                FNSTCW            // 保存协处理器控制字,用来恢复
                mov word ptr , 0x0E60   //截断, 64位浮点
                FLDCW               // 载入协处理器控制字,RC场已经修改
                       
                fistp   dword ptr                         //恢复FPU的取整方式
                FLDCW   
               
                pop eax
                ret
        }
}
宝宝的程序还可以继续精简
两个 FWAIT都不是必需的
仅在浮点存,且下个指令是读存储的数据时需要FWAIT

无心人 发表于 2009-2-18 09:13:16


double lbc_b32[] = {0.0,4294967296.0};
//实验证明zero5不能大于0.49999999999636
double zero5=      0.49999999999636;;

__declspec(naked)
DWORD __fastcall iSqrt_FPU1_lbc(DWORD n)
{
__asm
{
push ecx

shr ecx, 31
fld qword ptr
fild dword ptr
faddpst(1),st
fsqrt
fsubqword ptr
fistpdword ptr
pop eax
ret
}
}

__declspec(naked)
DWORD __fastcall iSqrt_FPU2_lbc(DWORD n)
{
__asm
{
or ecx,ecx
jnz next00
mov eax,0
ret
next00:
push ecx

shr ecx, 31
fld qword ptr
fild dword ptr
faddpst(1),st
fsqrt
fstpqword ptr

fwait
movecx,dword ptr
movedx,0xfff00000
moveax,0xfffff

andedx,ecx //阶码
andeax,ecx //尾数
shredx,20 //得到阶段码
addeax,0x100000 //设置位数最高有效位
movecx,1043
subecx,edx
shreax,cl //得到整数

pop ecx
ret
}
}

__declspec(naked)
DWORD __fastcall iSqrt_FPU3_lbc(DWORD n)
{
__asm
{
push ecx
shr ecx, 31
fld qword ptr
fild dword ptr
faddpst(1),st
fsqrt

//设置FPU的取整方式为了直接使用fistp浮点指令
FNSTCW            // 保存协处理器控制字,用来恢复
mov word ptr , 0x0E60   //截断, 64位浮点
FLDCW               // 载入协处理器控制字,RC场已经修改

fistp   dword ptr //恢复FPU的取整方式
FLDCW   

pop eax
ret
}
}

double b32[] = {0.0,4294967296.0};

__declspec(naked)
DWORD __fastcall iSqrt_FPU_yaos(DWORD n)
{
__asm
{
   push ecx
   sub esp, 4
   mov word ptr , 0x0E60
   fnstcw word ptr
   mov eax, ecx
   shr eax, 31
   fld qword ptr
   fild dword ptr
   faddp st(1), st
   fsqrt
   fldcw word ptr
   fistp dword ptr
   fldcw word ptr
   mov eax,
   add esp, 8
   ret

   }
}

__declspec(naked)
DWORD __fastcall iSqrt_FPU1_yaos(DWORD n)
{
__asm
{
push ecx
mov eax, ecx
    shr eax, 31
fld qword ptr
fild dword ptr
    faddp st(1), st
fsqrt
fisttp dword ptr
fwait
pop eax
ret
}
}

__declspec(naked)
DWORD __fastcall iSqrt_FPU2_yaos(DWORD n)
{
__asm
{
   push ecx
   mov eax, ecx   
   and eax, 0x80000000
   shr eax, 31
   fld qword ptr
   fild dword ptr
   faddp st(1), st
   fsqrt
   sub esp, 8
   fstp qword ptr
   fwait
   mov edx, dword ptr
   mov eax, edx
   and edx,0x7ff00000
   and eax,0xfffff
   shr edx, 20
   or eax, 0x100000
   xchg ecx, edx
   sub ecx, 1043
   neg ecx
   shr eax, cl
   xchg edx, ecx
   add esp, 12
   or ecx, ecx
   cmove eax, ecx
   ret
   }
}
完全测试
n: 0-0x10000
iSqt_FPU1_lbc#: 0.00234 s
iSqt_FPU2_lbc#: 0.00234 s
iSqt_FPU3_lbc#: 0.00234 s
iSqt_FPU_yaos#: 0.00234 s
iSqt_FPU1_yaos#: 0.00235 s
iSqt_FPU2_yaos#: 0.00234 s


n: 0-0x10000000
iSqt_FPU1_lbc#: 9.62084 s
iSqt_FPU2_lbc#: 9.64661 s
iSqt_FPU3_lbc#: 9.62920 s
iSqt_FPU_yaos#: 9.61824 s
iSqt_FPU1_yaos#: 9.62351 s
iSqt_FPU2_yaos#: 9.61847 s

================================
iSqrt_FPU1_yaos是SSE3指令

无心人 发表于 2009-2-18 09:36:57

n: 0-0x10000
iSqt_FPU1_lbc#: 0.00234 s
iSqt_FPU2_lbc#: 0.00234 s
iSqt_FPU3_lbc#: 0.00234 s
iSqt_FPU_yaos#: 0.00234 s
iSqt_FPU1_yaos#: 0.00234 s
iSqt_FPU2_yaos#: 0.00234 s
iSqt_gxq_ALU#: 0.00378 s


n: 0-0x10000000
iSqt_FPU1_lbc#: 9.61900 s
iSqt_FPU2_lbc#: 9.66175 s
iSqt_FPU3_lbc#: 9.66552 s
iSqt_FPU_yaos#: 9.63164 s
iSqt_FPU1_yaos#: 9.61888 s
iSqt_FPU2_yaos#: 9.61667 s
iSqt_gxq_ALU#: 15.48249 s //版本3

n: 0-0x10000
iSqt_FPU1_lbc#: 0.00234 s
iSqt_FPU2_lbc#: 0.00234 s
iSqt_FPU3_lbc#: 0.00234 s
iSqt_FPU_yaos#: 0.00234 s
iSqt_FPU1_yaos#: 0.00234 s
iSqt_FPU2_yaos#: 0.00234 s
iSqt_gxq_ALU#: 0.00559 s


n: 0-0x10000000
iSqt_FPU1_lbc#: 9.62917 s
iSqt_FPU2_lbc#: 9.62330 s
iSqt_FPU3_lbc#: 9.62190 s
iSqt_FPU_yaos#: 9.62101 s
iSqt_FPU1_yaos#: 9.62660 s
iSqt_FPU2_yaos#: 9.67119 s
iSqt_gxq_ALU#: 23.00808 s //版本2


n: 0-0x10000
iSqt_FPU1_lbc#: 0.00234 s
iSqt_FPU2_lbc#: 0.00235 s
iSqt_FPU3_lbc#: 0.00234 s
iSqt_FPU_yaos#: 0.00234 s
iSqt_FPU1_yaos#: 0.00234 s
iSqt_FPU2_yaos#: 0.00234 s
iSqt_gxq_ALU#: 0.00189 s


n: 0-0x10000000
iSqt_FPU1_lbc#: 9.62116 s
iSqt_FPU2_lbc#: 9.61972 s
iSqt_FPU3_lbc#: 9.61780 s
iSqt_FPU_yaos#: 9.61988 s
iSqt_FPU1_yaos#: 9.62212 s
iSqt_FPU2_yaos#: 9.62422 s
iSqt_gxq_ALU#: 7.02810 s//版本1

gxqcn 发表于 2009-2-18 09:52:57

这么说,CPU 的 ALU 比 FPU 提速幅度更大?:Q:
如果真是这样的,发展基于整型指令的算法将更具竞争力?:lol

liangbch 发表于 2009-2-18 10:32:59

楼主辛苦了

无心人 发表于 2009-2-18 10:34:05

:)

关键是ALU算法并不是最好的
这就是为什么Intel推SIMD的原因

也许你的算法改SSE2更快

无心人 发表于 2009-2-18 10:35:10

:lol

你们俩有时间测下我改的
宝宝和我的三个汇编的数据
FPU1_yaos 就别测了

看是否我改的快了
或者反而慢了
页: 1 2 3 4 5 6 7 8 9 10 [11] 12 13 14 15
查看完整版本: 二进制32位整数快速平方根