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

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

[复制链接]
 楼主| 发表于 2009-2-17 16:17:08 | 显示全部楼层
我测试下吧
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-2-17 17:02:38 | 显示全部楼层
测试环境: CPU: Intel Pentium4 2.6G L1 data 8KB, L1 trace 12KB L2 cache 512KB RAM: DDR 768MB OS: windows XP compiler: VC++6.0 release Test case1: n=0 to 65535 iSqt_c1_lbc#: 0.00082 s iSqt_FPU1_lbc#: 0.00095 s iSqt_FPU3_lbc#: 0.00127 s iSqt_FPU2_lbc#: 0.00146 s iSqt_c2_lbc#: 0.00151 s iSqt_gxq_c#: 0.00173 s iSqt_FPU1_yaos#: 0.00220 s iSqt_FPU_yaos#: 0.00235 s iSqt_FPU2_yaos#: 0.00246 s iSqt_ref#: 0.00306 s iSqt_16#: 0.00398 s iSqt_gxq_90#: 0.00434 s (新增,90楼那个版本) iSqt_GxQ_asm#: 0.00449 s Test case2: n=0- 2^28-1 iSqt_FPU1_lbc#: 3.97569 s iSqt_FPU3_lbc#: 5.32763 s iSqt_FPU2_lbc#: 7.59953 s iSqt_gxq_c#: 7.64778 s iSqt_c1_lbc#: 8.14219 s iSqt_FPU1_yaos#: 9.24091 s iSqt_FPU_yaos#: 9.51267 s iSqt_c2_lbc#: 10.19276 s iSqt_FPU2_yaos#: 10.54652 s iSqt_ref#: 12.78721 s iSqt_16#: 14.57529 s iSqt_gxq_90#: 18.04432 s (新增,90楼那个版本) iSqt_GxQ_asm#: 18.64220 s
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-17 19:09:14 | 显示全部楼层
宝宝: 今天看你42# FPU3代码除了你么处理esp外, 你也么恢复ecx啊 另外,似乎是连续的两个fntstcw, fldcw造成的你的代码速度比俺的快 依据的什么原理??
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-2-17 21:24:26 | 显示全部楼层

回复 93# 无心人 的帖子

为什么我的版本比你的快,我没有仔细分析过,连续使用两个fntstcw没有什么特别的道理,我的原则是指令数尽可能少,另外要做到浮点寄存器栈的平衡。 我确实没有回回复ecx寄存器,我记得按照函数调用规则,如果你在子程序中修改了esi,edi,ebx,esp,ebp 等寄存器,你必须恢复它,但是你可以在子程序中仍以修改eax,edx,ecx 的值,调用者不能假定这些寄存器没有变化。 但是如果指定了__fastcall关键字,是否必须保证调用子程序后不修改ecx的值,我刚刚查阅了一些资料,但依然没有找到确切的答案。我是假定在__fastcall子程序中可以修改ecx 的值的。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-17 21:54:55 | 显示全部楼层
几乎同样的功能 几乎同样的指令 一个9.24 一个5.32 到底差距在哪里啊?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-2-17 22:03:38 | 显示全部楼层

我写的三个ALU汇编版本

  1. __declspec(naked)
  2. UINT32 __fastcall iSqrt_ALU( UINT32 n )
  3. {
  4. __asm push esi;
  5. __asm push edi;
  6. __asm xor eax, eax;
  7. #if 1 /* Ver1: 指令数最少,但含跳转 */
  8. #define SQRT_CORE_ASM(x) \
  9. __asm lea edx, [eax+(1UL<<(x))] \
  10. __asm shr eax, 1 \
  11. __asm cmp ecx, edx \
  12. __asm jb L_##x \
  13. __asm sub ecx, edx \
  14. __asm add eax, (1UL<<(x)) \
  15. __asm L_##x:
  16. #elif 0 /* Ver2: 常规指令,无跳转 */
  17. #define SQRT_CORE_ASM(x) \
  18. __asm mov edi, 1UL<<(x) \
  19. __asm lea edx, [eax+edi] \
  20. __asm shr eax, 1 \
  21. __asm cmp ecx, edx \
  22. __asm sbb esi, esi \
  23. __asm not esi \
  24. __asm and edx, esi \
  25. __asm and edi, esi \
  26. __asm sub ecx, edx \
  27. __asm add eax, edi
  28. #else /* Ver3: 含CMOVcc指令,无跳转 */
  29. #define SQRT_CORE_ASM(x) \
  30. __asm lea edx, [eax+(1UL<<(x))] \
  31. __asm shr eax, 1 \
  32. __asm mov esi, ecx \
  33. __asm sub ecx, edx \
  34. __asm lea edi, [eax+(1UL<<(x))] \
  35. __asm cmovb ecx, esi \
  36. __asm cmovae eax, edi
  37. #endif
  38. SQRT_CORE_ASM(30);
  39. SQRT_CORE_ASM(28);
  40. SQRT_CORE_ASM(26);
  41. SQRT_CORE_ASM(24);
  42. SQRT_CORE_ASM(22);
  43. SQRT_CORE_ASM(20);
  44. SQRT_CORE_ASM(18);
  45. SQRT_CORE_ASM(16);
  46. SQRT_CORE_ASM(14);
  47. SQRT_CORE_ASM(12);
  48. SQRT_CORE_ASM(10);
  49. SQRT_CORE_ASM(8);
  50. SQRT_CORE_ASM(6);
  51. SQRT_CORE_ASM(4);
  52. SQRT_CORE_ASM(2);
  53. SQRT_CORE_ASM(0);
  54. #undef SQRT_CORE_ASM
  55. __asm pop edi;
  56. __asm pop esi;
  57. __asm ret;
  58. }
复制代码
其对应的C代码是一样的,只是采用了不同的汇编手法。 测试结果如下:
n: 0-0x10000 iSqt_ref#: 0.00098 s iSqt_c1_lbc#: 0.00071 s iSqt_c2_lbc#: 0.00133 s iSqt_FPU1_lbc#: 0.00092 s iSqt_FPU2_lbc#: 0.00134 s iSqt_FPU3_lbc#: 0.00118 s iSqt_FPU_yaos#: 0.00217 s iSqt_FPU1_yaos#: 0.00217 s iSqt_FPU2_yaos#: 0.00208 s iSqt_gxq_c#: 0.00140 s iSqt_GxQ_asm#: 0.00471 s iSqt_ALU_v1#: 0.00115 s iSqt_ALU_v2#: 0.00580 s iSqt_ALU_v3#: 0.00426 s iSqt_16#: 0.00298 s n: 0-0x4000000 iSqt_ref#: 1.03851 s iSqt_c1_lbc#: 2.05060 s iSqt_c2_lbc#: 1.94235 s iSqt_FPU1_lbc#: 0.99109 s iSqt_FPU2_lbc#: 1.41954 s iSqt_FPU3_lbc#: 1.24257 s iSqt_FPU_yaos#: 2.31683 s iSqt_FPU1_yaos#: 2.38967 s iSqt_FPU2_yaos#: 2.22774 s iSqt_gxq_c#: 1.11229 s iSqt_GxQ_asm#: 5.01363 s iSqt_ALU_v1#: 1.17843 s iSqt_ALU_v2#: 6.18305 s iSqt_ALU_v3#: 4.54953 s iSqt_16#: 2.95849 s
测试平台为:Windows XP SP3, P4 2.93GHz
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-17 22:11:44 | 显示全部楼层
46#代码存在冗余 需要修改
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-17 22:15:36 | 显示全部楼层
如果我的Core2Xeon测试 应该是你的V3版本最好了
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-17 22:38:23 | 显示全部楼层
  1. __declspec(naked)
  2. DWORD __fastcall iSqrt_FPU1_yaos(DWORD n)
  3. {
  4. __asm
  5. {
  6. sub esp, 8
  7. mov [esp + 4], ecx
  8. fnstcw word ptr [esp]
  9. fnstcw word ptr [esp + 2]
  10. or word ptr [esp], 0x0E60
  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. }
复制代码
宝宝的代码里我的函数FPU1应该是这样的 稍微优化了点 执行时间减少了至少40% 我明天去学校看我机器里的代码 可能存在版本差异
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-18 07:51:09 | 显示全部楼层
今天早上 翻MMX的书 看到说,内存的内部和全部 即128位内部的64位,64位内部的32位等等。。。 如果同时发生写和读 将发生阻塞 可能是我程序代码速度慢的原因
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

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

GMT+8, 2024-11-22 00:23 , Processed in 0.030648 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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