无心人 发表于 2009-2-12 15:55:41

你39#代码存在问题
首行应该是or ecx, ecx吧

liangbch 发表于 2009-2-12 16:03:46

回复 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 编辑 ]

gxqcn 发表于 2009-2-12 16:26:35

我也写了个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;
}

无心人 发表于 2009-2-12 16:42:16

宝宝:
减0.5不是个好办法,或许因为别的函数改变了RC, 就反而得不到正确的数值了

锅老大:
你这算偷懒的
在函数外
控制RC获得的性能提升有限的

liangbch 发表于 2009-2-12 16:44:55

gxq 的这个版本最简单,但是在程序开头改变了FPU控制字,不知到在运行期间,是不是会影响的一些浮点数学函数。

无心人 发表于 2009-2-12 17:07:17


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的
会造成函数结果错误
输入小的时候测试不到

无心人 发表于 2009-2-12 17:19:22

下面就是寻求执行时间少于60周期的整数算法
考虑乘法总延迟16周期
除法总延迟是50周期

所以
1、不能出现除法
2、乘法最多2个

liangbch 发表于 2009-2-12 17:26:29

你的FPU2的版本写成
sub edx, 1022
   mov ecx, 21
   sub ecx, edx


我的则做了优化,直接写成以下形式,实际上是等价的
movecx,1043
subecx,edx

无心人 发表于 2009-2-12 17:28:50

:lol

我不理解你的做法
所以改了啊

无心人 发表于 2009-2-12 17:52:24

呵呵

    在持续改进FPU2函数,增加了非跳转处理0的代码

   另外,FWAIT似乎并不必须吧
页: 1 2 3 4 [5] 6 7 8 9 10 11 12 13 14
查看完整版本: 二进制32位整数快速平方根