找回密码
 欢迎注册
楼主: 无心人

[讨论] 二进制32位整数快速平方根

[复制链接]
 楼主| 发表于 2009-2-18 07:53:30 | 显示全部楼层

  1. __declspec(naked)
  2. DWORD __fastcall iSqrt_FPU1_yaos(DWORD n)
  3. {
  4. __asm
  5. {
  6.    push ecx
  7.    sub esp, 4
  8.    mov word ptr [esp], 0x0E60
  9.    fnstcw word ptr [esp + 2]
  10.    mov eax, ecx  
  11.    shr eax, 31
  12.    fld qword ptr [b32 + eax * 8]
  13.    fild dword ptr [esp + 4]
  14.    faddp st(1), st
  15.    fsqrt
  16.    fldcw word ptr [esp]
  17.    fistp dword ptr [esp + 4]
  18.    fldcw word ptr [esp + 2]
  19.    mov eax, [esp + 4]
  20.    add esp, 8
  21.    ret
  22.    }
  23. }
复制代码
再次优化99#代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-18 08:51:25 | 显示全部楼层

宝宝的FPU3版本可修改为

  1. __declspec(naked)
  2. DWORD __fastcall iSqrt_FPU3_lbc(DWORD n)
  3. {
  4. __asm
  5. {
  6. push ecx
  7. shr ecx, 31
  8. fld qword ptr [lbc_b32 + ecx * 8]
  9. fild dword ptr [esp]
  10. faddp  st(1),st
  11. fsqrt

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

  17. fistp   dword ptr [esp]

  18. //恢复FPU的取整方式
  19. FWAIT
  20. FLDCW   [esp-4]

  21. pop eax
  22. ret
  23. }
  24. }
复制代码
比较了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 | 显示全部楼层

  1. __declspec(naked)
  2. DWORD __fastcall iSqrt_FPU3_lbc(DWORD n)
  3. {
  4.         __asm
  5.         {
  6.                 push ecx
  7.                 shr ecx, 31
  8.                 fld qword ptr [lbc_b32 + ecx * 8]
  9.                 fild dword ptr [esp]
  10.                 faddp  st(1),st
  11.                 fsqrt
  12.                        
  13.                 //设置FPU的取整方式  为了直接使用fistp浮点指令
  14.                 FNSTCW  [esp-4]            // 保存协处理器控制字,用来恢复
  15.                 mov word ptr [esp-6], 0x0E60     //截断, 64位浮点
  16.                 FLDCW   [esp-6]            // 载入协处理器控制字,RC场已经修改
  17.                        
  18.                 fistp   dword ptr [esp]                        //恢复FPU的取整方式
  19.                 FLDCW   [esp-4]
  20.                
  21.                 pop eax
  22.                 ret
  23.         }
  24. }
复制代码
宝宝的程序还可以继续精简
两个 FWAIT都不是必需的
仅在浮点存,且下个指令是读存储的数据时需要FWAIT
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-18 09:13:16 | 显示全部楼层

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

  4. __declspec(naked)
  5. DWORD __fastcall iSqrt_FPU1_lbc(DWORD n)
  6. {
  7. __asm
  8. {
  9. push ecx

  10. shr ecx, 31
  11. fld qword ptr [lbc_b32 + ecx  * 8]
  12. fild dword ptr [esp]
  13. faddp  st(1),st
  14. fsqrt
  15. fsub  qword ptr [zero5]
  16. fistp  dword ptr [esp]
  17. pop eax
  18. ret
  19. }
  20. }

  21. __declspec(naked)
  22. DWORD __fastcall iSqrt_FPU2_lbc(DWORD n)
  23. {
  24. __asm
  25. {
  26. or ecx,ecx
  27. jnz next00
  28. mov eax,0
  29. ret
  30. next00:
  31. push ecx

  32. shr ecx, 31
  33. fld qword ptr [lbc_b32 + ecx * 8]
  34. fild dword ptr [esp]
  35. faddp  st(1),st
  36. fsqrt
  37. fstp  qword ptr [esp-8]

  38. fwait
  39. mov  ecx,dword ptr [esp-4]
  40. mov  edx,0xfff00000
  41. mov  eax,0xfffff

  42. and  edx,ecx //阶码
  43. and  eax,ecx //尾数
  44. shr  edx,20 //得到阶段码
  45. add  eax,0x100000 //设置位数最高有效位
  46. mov  ecx,1043
  47. sub  ecx,edx
  48. shr  eax,cl //得到整数

  49. pop ecx
  50. ret
  51. }
  52. }

  53. __declspec(naked)
  54. DWORD __fastcall iSqrt_FPU3_lbc(DWORD n)
  55. {
  56. __asm
  57. {
  58. push ecx
  59. shr ecx, 31
  60. fld qword ptr [lbc_b32 + ecx * 8]
  61. fild dword ptr [esp]
  62. faddp  st(1),st
  63. fsqrt

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

  68. fistp   dword ptr [esp] //恢复FPU的取整方式
  69. FLDCW   [esp-4]

  70. pop eax
  71. ret
  72. }
  73. }
复制代码

  1. double b32[] = {0.0,4294967296.0};

  2. __declspec(naked)
  3. DWORD __fastcall iSqrt_FPU_yaos(DWORD n)
  4. {
  5. __asm
  6. {
  7.    push ecx
  8.    sub esp, 4
  9.    mov word ptr [esp], 0x0E60
  10.    fnstcw word ptr [esp + 2]
  11.    mov eax, ecx  
  12.    shr eax, 31
  13.    fld qword ptr [b32 + eax * 8]
  14.    fild dword ptr [esp + 4]
  15.    faddp st(1), st
  16.    fsqrt
  17.    fldcw word ptr [esp]
  18.    fistp dword ptr [esp + 4]
  19.    fldcw word ptr [esp + 2]
  20.    mov eax, [esp + 4]
  21.    add esp, 8
  22.    ret

  23.    }
  24. }

  25. __declspec(naked)
  26. DWORD __fastcall iSqrt_FPU1_yaos(DWORD n)
  27. {
  28. __asm
  29. {
  30. push ecx  
  31. mov eax, ecx
  32.     shr eax, 31
  33. fld qword ptr [b32 + eax * 8]
  34. fild dword ptr [esp]
  35.     faddp st(1), st
  36. fsqrt
  37. fisttp dword ptr [esp]
  38. fwait
  39. pop eax
  40. ret
  41. }
  42. }

  43. __declspec(naked)
  44. DWORD __fastcall iSqrt_FPU2_yaos(DWORD n)
  45. {
  46. __asm
  47. {
  48.    push ecx
  49.    mov eax, ecx   
  50.    and eax, 0x80000000
  51.    shr eax, 31
  52.    fld qword ptr [b32 + eax * 8]
  53.    fild dword ptr [esp]
  54.    faddp st(1), st
  55.    fsqrt
  56.    sub esp, 8
  57.    fstp qword ptr [esp]
  58.    fwait
  59.    mov edx, dword ptr [esp + 4]
  60.    mov eax, edx
  61.    and edx,0x7ff00000
  62.    and eax,0xfffff
  63.    shr edx, 20
  64.    or eax, 0x100000
  65.    xchg ecx, edx
  66.    sub ecx, 1043
  67.    neg ecx
  68.    shr eax, cl
  69.    xchg edx, ecx
  70.    add esp, 12
  71.    or ecx, ecx
  72.    cmove eax, ecx
  73.    ret
  74.    }
  75. }
复制代码
完全测试
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
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-2-18 09:52:57 | 显示全部楼层
这么说,CPU 的 ALU 比 FPU 提速幅度更大?
如果真是这样的,发展基于整型指令的算法将更具竞争力?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-2-18 10:32:59 | 显示全部楼层
楼主辛苦了
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-18 10:34:05 | 显示全部楼层


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

也许你的算法改SSE2更快
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-18 10:35:10 | 显示全部楼层


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

看是否我改的快了
或者反而慢了
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-5-4 22:01 , Processed in 0.043193 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表