首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >gcc9+模优化背后的数学

gcc9+模优化背后的数学
EN

Stack Overflow用户
提问于 2018-11-21 14:53:19
回答 1查看 343关注 0票数 6

背景

我在玩c中的素数时,偶然发现了gcc主干中的一个新优化(将是9.x版本),它将模数比较优化为0,并使用幻数进行比较。换句话说,x%prime==0变成了x*Magic_mul<=Magic_cmp

代码语言:javascript
复制
_Bool mod(unsigned x){return x % Constant == 0;}

mod:
  imul edi, edi, Magic_mul
  cmp edi, Magic_cmp
  setbe al

详细信息

在看到asm输出的基础上,它对所有整数(至少是素数)进行了这些优化--我将它们转换为十六进制以帮助查看模式,但这一点目前并不明显。

代码语言:javascript
复制
//32bit examples for _Bool mod_n(unsigned x){return x%n==0;};
//note: parameter is unsigned but it becomes a signed multiply
x%3==0;  // x*0xAAAAAAAB <= 0x55555555
x%5==0;  // x*0xCCCCCCCD <= 0x33333333
x%7==0;  // x*0xB6DB6DB7 <= 0x24924924
x%11==0; // x*0xBA2E8BA3 <= 0x1745D174
x%13==0; // x*0xC4EC4EC5 <= 0x13B13B13
x%17==0; // x*0xF0F0F0F1 <= 0x0F0F0F0F
x%19==0; // x*0x286BCA1B <= 0x0D79435E
x%23==0; // x*0xE9BD37A7 <= 0x0B21642C
x%29==0; // x*0x4F72C235 <= 0x08D3DCB0
x%31==0; // x*0xBDEF7BDF <= 0x08421084
x%37==0; // x*0x914C1BAD <= 0x06EB3E45
x%41==0; // x*0xC18F9C19 <= 0x063E7063
x%43==0; // x*0x2FA0BE83 <= 0x05F417D0
x%47==0; // x*0x677D46CF <= 0x0572620A
x%53==0; // x*0x8C13521D <= 0x04D4873E
x%59==0; // x*0xA08AD8F3 <= 0x0456C797
x%61==0; // x*0xC10C9715 <= 0x04325C53
x%67==0; // x*0x07A44C6B <= 0x03D22635
x%71==0; // x*0xE327A977 <= 0x039B0AD1
x%73==0; // x*0xC7E3F1F9 <= 0x0381C0E0
x%79==0; // x*0x613716AF <= 0x033D91D2
x%83==0; // x*0x2B2E43DB <= 0x03159721
x%89==0; // x*0xFA3F47E9 <= 0x02E05C0B
x%97==0; // x*0x5F02A3A1 <= 0x02A3A0FD
///...and even up to 64bit
x%4294967291==0; //x*0x70A3D70A33333333 <= 0x100000005

我检查了黑客的喜悦“整数除以常量”,这似乎是乘法和右移的余数的特殊情况,但我不确定。有一个计算相同乘数常数的以黑客为乐,所以看起来很有希望。我猜神奇的比较常数代替了shift并将其比较为零,但是我很难想象2s补码,以及移位是算术的还是逻辑的。

问题

这背后是否有一些数学,还是用二进制表示的其他方式确定的数字?

Implications

由于这是简单的整数乘和比较,这可以大大加快(或减少内存占用)检查素数,使用向量扩展/本质。如果数学可以扩展到超过64位,它可能会使找到大数素数的速度快得多?

EN

回答 1

Stack Overflow用户

发布于 2018-11-21 15:19:08

以3为例。

0xAB *3= 0x201,因此,模0x100,0xAB为1 / 3,相反,0xAB *3≡1。

任何8位无符号整数n都可以表示为n= 3*k + r,r< 3,k最多为0x55 (小数85,积分为255 / 3)。

所以我们有选择:

  1. R=0⇒n* 0xAB = 3k * 0xAB =k* (3 * 0xAB)≡k*1=k≤0x55。
  2. R=1⇒n* 0xAB = 3k * 0xAB + 0xAB;由于3k * 0xAB最多为0x55 (mod 0x100),将其添加到0xAB不会溢出,所以3k * 0xAB + 0xAB≥0xAB > 0x55。
  3. R=2⇒n* 0xAB = 3k * 0xAB + 0x156≡3k * 0xAB + 0x56≥0x56 > 0x55 (同2.)
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53414711

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档