找回密码
 欢迎注册
查看: 9930|回复: 7

[提问] 请教一下关于VC处理对2的幂取模的问题

[复制链接]
发表于 2010-7-27 22:14:47 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?欢迎注册

×
对2的幂取模,按理说利用余数 = 被除数 - 商*2^k就可以了,而有符号数对2的k次方求商应该也很高效:
mov eax, 被除数
cdq
and edx,1F
add eax,edx
sar eax,5 ;这时eax已经得到了商

shl eax, k
sub 被除数, eax ;此时可以得到余数
以上可以实现无分支取模

在VC6里面,其实现为如下代码:
00401000   mov eax,dword ptr ss:[esp+4] ;[esp+4]保存了被除数
00401004   mov ecx,eax
00401006   and ecx,8000001F
0040100C   jns short TestDiv.00401013
0040100E   dec ecx
0040100F   or ecx,FFFFFFE0
00401012   inc ecx
00401013   push ecx
00401014   push 20
00401016   push eax
00401017   push TestDiv.004130D8        ;  ASCII "%d %% %d = %d"
0040101C   call TestDiv.004010B0
00401021   add esp,10
其实现产生了分支语句,明显效率不高,请教一下这样的处理是否有其他考虑呢?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-7-27 23:09:50 | 显示全部楼层
我就纳闷,无论是周期总和还是流水线问题,VC的写法都不高效啊,我还开了O2的,可能他们考虑到某些我没想到的方面吧。
写了个程序测试一下,看看在有符号数值范围内有没有某个特殊的数值存在问题。
  1. int MyModBy32(int n)
  2. {
  3.   __asm
  4.   {
  5.     mov eax, n
  6.     cdq
  7.     and edx,0x1F
  8.     add eax,edx
  9.     sar eax,5 ;
  10.    
  11.     shl eax, 5
  12.     sub n, eax ;
  13.   }
  14.   
  15.   return n;
  16. }

  17. int func1(int n)
  18. {
  19.   return n % 32;
  20. }

  21. int _tmain(int argc, _TCHAR* argv[])
  22. {
  23.   int r1, r2;
  24.   for (int i = 1; i; i++)
  25.   {
  26.     r1 = func1(i);
  27.     r2 = MyModBy32(i);
  28.     printf("%d %% %d = %d\r\n", i, 32, r1);
  29.     printf("%d %% %d = %d\r\n", i, 32, r2);
  30.     if (r1 != r2)
  31.     {
  32.       puts("error");
  33.       break;
  34.     }
  35.   }
  36.   
  37.   system("pause");
  38.   return 0;
  39. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-7-28 01:50:36 | 显示全部楼层
VC产生的代码中,其原理貌似也简单,在对有符号数求余的时候,VC规定余数的符号由被除数决定,使得满足公式“余数 = 被除数 - 商*除数”,于是遇到一个问题,也就是负余数的处理。对于2的k次方取余来说,大多数余数的值只需取得被除数二进制数值中的最后k位的值即可,负数则还需k位之前补1,于是可以的到以下代码,设k为5:
  mov reg, 被除数
  and reg,8000001F
  jns LAB1
  or reg, FFFFFFE0
LAB1:

以上代码对余数非0是没有问题的,但是如果余数为0,则按以上代码计算结果为FFFFFFE0,是错误的,于是加以调整,调整办法为or运算前后减一加一。对于余数不为0的,此调整不影响计算结果;对于余数为0的,末尾k位全部为0值,此时减一得到末尾k位为1,or运算得到-1,最后加一得到余数值为0,调整后的代码如下:
  mov reg, 被除数
  and reg,8000001F
  jns LAB1
  dec reg
  or reg, FFFFFFE0
  inc reg
LAB1:

本人非数学专业,研究数学是工作之余的兴趣爱好,以上言论也不能算是严密的数学论证,最多只是猜测。论坛数学高手如云,故前来请教一二,若猜测有误,望不吝指点。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-7-28 01:59:50 | 显示全部楼层
不知道是怎么回事,写帖子内容的文本框很小,截图无法上传。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-7-28 07:55:08 | 显示全部楼层
不知道是怎么回事,写帖子内容的文本框很小,截图无法上传。
backer 发表于 2010-7-28 01:59


你可点“高级回复”模式,如觉窗口不够大,右上角还有最大化、新开窗口等按钮。
在“高级回复”模式里下面有个“添加附件”链接,点一下即可上传附件(注意,单个附件不得超过500KB)。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-7-28 13:28:08 | 显示全部楼层
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2010-7-28 13:29:40 | 显示全部楼层
点附件没有反映,惭愧,完全不懂网页方面
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2010-7-28 13:53:18 | 显示全部楼层
你的IE版本太老了,请升级一下;或安装Firefox吧。

IE8 下的效果图

IE8 下的效果图
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

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

GMT+8, 2024-5-19 10:18 , Processed in 0.050375 second(s), 20 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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