首行应该是or ecx, ecx吧
回复 41# 无心人 的帖子
是,不小心写错了,已修改下面贴出在无心人的基础上,经我改写的3个FPU的版本。
double b32[] = {0.0,4294967296.0};
//实验证明zero5不能大于0.49999999999636
double zero5= 0.49999999999636;;
__declspec(naked)
DWORD __fastcall iSqrt_FPU1(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(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(DWORD n)
{
__asm
{
push ecx
shr ecx, 31
fld qword ptr
fild dword ptr
faddpst(1),st
fsqrt
//设置FPU的取整方式为了直接使用fistp浮点指令
FNSTCW // 保存协处理器控制字,用来恢复
FNSTCW // 保存协处理器控制字,用来修改
FWAIT
ORword ptr , 0x0F00 // 改为 RC=11使FPU向零取整
FLDCW // 载入协处理器控制字,RC场已经修改
fistp dword ptr
//恢复FPU的取整方式
FWAIT
FLDCW
pop eax
ret
}
}
[ 本帖最后由 liangbch 于 2009-2-13 10:28 编辑 ] 我也写了个FPU的版本,有兴趣的朋友可把相关函数添加进来一并测试一下:#include < stdio.h >
#include < stdlib.h >
#include < time.h >
#include < float.h >
typedef unsigned int UINT32;
typedef UINT32 __fastcall func_t( UINT32 );
_declspec(naked)
UINT32 __fastcall Sqrt_43F( UINT32 n )
{
__asm
{
xor eax, eax;
push eax;
push ecx;
fild qword ptr;
fsqrt;
pop eax;
fistp dword ptr;
pop eax;
ret;
}
}
#define FN(ID) Sqrt_##ID##F /* ex.: Sqrt_43F */
void test_fun( void )
{
UINT32 i, j;
UINT32 fID[] = { 43, /* ... */ };
func_t * funcTable[] = { FN(43), /* FN(..),... */ };
func_t * pfn;
#ifdef _DEBUG
UINT32 m = 256;
#else
UINT32 m = 1UL<<28;
time_t t;
#endif
printf( "\n\nn: 0-0x%x\n", m );
for ( i=0; i<sizeof(fID)/sizeof(fID); ++i )
{
pfn = funcTable;
#ifdef _DEBUG
// check result
for ( j=0; j<=m; ++j )
{
printf( "Sqrt_%uF(%u)=%u\n", fID, j, pfn(j) );
}
system( "pause" );
#else
t = time(NULL);
for ( j=m; 0!=j; --j )
{
pfn(j);
}
t = time(NULL)-t;
printf( "%u#: %u s\n", fID, t );
#endif
}
}
int main(int argc, char* argv[])
{
_control87( RC_CHOP | PC_64, MCW_RC | MCW_PC );
test_fun();
return 0;
} 宝宝:
减0.5不是个好办法,或许因为别的函数改变了RC, 就反而得不到正确的数值了
锅老大:
你这算偷懒的
在函数外
控制RC获得的性能提升有限的 gxq 的这个版本最简单,但是在程序开头改变了FPU控制字,不知到在运行期间,是不是会影响的一些浮点数学函数。
double b32[] = {0.0,4294967296.0};
__declspec(naked)
DWORD __fastcall iSqrt_FPU(DWORD n)
{
__asm
{
push ecx
sub esp, 4
fnstcw word ptr
mov edx, dword ptr
or dword ptr , 0x0C00
mov eax, ecx
and eax, 0x80000000
shr eax, 31
fld qword ptr
fild dword ptr
faddp st(1), st
fsqrt
fldcw word ptr
fistp dword ptr
mov dword ptr , edx
fldcw word ptr
add esp, 4
pop eax
ret
}
}
__declspec(naked)
DWORD iSqrt_FPU1(DWORD n)
{
__asm
{
sub esp, 4
fnstcw word ptr
mov edx, dword ptr
or dword ptr , 0x0C00
mov eax,
and eax, 0x80000000
shr eax, 31
fld qword ptr
fild dword ptr
faddp st(1), st
fsqrt
fldcw word ptr
fistp dword ptr
mov dword ptr , edx
fldcw word ptr
add esp, 4
mov eax,
ret
}
}
__declspec(naked)
DWORD __fastcall iSqrt_FPU2(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
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
}
}
比较时间
FPU2 < FPU < FPU1
另外,程序开始就改变RC的
会造成函数结果错误
输入小的时候测试不到 下面就是寻求执行时间少于60周期的整数算法
考虑乘法总延迟16周期
除法总延迟是50周期
所以
1、不能出现除法
2、乘法最多2个 你的FPU2的版本写成
sub edx, 1022
mov ecx, 21
sub ecx, edx
我的则做了优化,直接写成以下形式,实际上是等价的
movecx,1043
subecx,edx :lol
我不理解你的做法
所以改了啊 呵呵
在持续改进FPU2函数,增加了非跳转处理0的代码
另外,FWAIT似乎并不必须吧