背景
当我偶然发现gcc主干(将是9.x版)中的一项新优化将c的质数比较优化为0变为整数乘法并使用魔数(Magic Number)进行比较时,我正在使用c中的质数。换句话说x%prime==0
变成x*Magic_mul<=Magic_cmp
_Bool mod(unsigned x){return x % Constant == 0;}
mod:
imul edi, edi, Magic_mul
cmp edi, Magic_cmp
setbe al
详细信息
基于看到的asm输出,它将对所有整数(至少是质数)进行这些优化,然后将它们转换为十六进制以帮助查看模式,但目前还不是很明显。
//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
我检查了hacker's delight "INTEGER DIVISION BY CONSTANTS",看来这可能是乘法和右移的余数的一种特殊情况,但我不确定。有一个form on hacker's delight可以计算这些相同的乘数常量,因此这似乎很有希望。我猜魔术比较常数代替了移位并将其与零进行比较,但是我在可视化2s补码以及移位是算术还是逻辑上遇到了麻烦。
问题
这背后是否有一些数学运算,还是使用二进制表示以其他方式确定了数字?
的含义
由于这是简单的整数乘法和比较,因此可以使用 vector 扩展/本征函数极大地加快(或减少其内存占用)检查素数的速度。如果算术可以扩展到64位以上,那么可能会更快地找到大型Big-Number素数吗?
最佳答案
以3为例。
0xAB * 3 = 0x201,因此,模0x100、0xAB为1/3,反之为0xAB * 3≡1。
任何8位无符号整数n都可以表示为n = 3 * k + r,r
因此,我们有以下选择:
关于c - gcc9 +模数优化背后的数学,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53414711/