如果右侧为常数,可转换成乘法、右移和減法。现代的编译器都会做这个优化,例如
//mod.cunsigneda=123;intmain(){returna%13;}
使用 clang -c -S mod.c 输出汇编
movl$13,%eaxmovl$0,-4(%rbp)movl_a(%rip),%ecxmovl%eax,-8(%rbp)##4-byteSpillmovl%ecx,%eaxxorl%edx,%edxmovl-8(%rbp),%ecx##4-byteReloaddivl%ecxmovl%edx,%eax这是直接翻译,用 divl 做除数,这指令同时能获得余数(edx ),但 divl 是很慢的。
然而,使用优化的话 clang -c -S -O3 mod.c
movl_a(%rip),%eaximulq$1321528399,%rax,%rcx##imm=0x4EC4EC4Fshrq$34,%rcximull$13,%ecx,%ecxsubl%ecx,%eax
解释一下,因为 1321528399 / 2^34 ≈ 1 / 13
a%13=a-(a/13)*13=a-uint32_t((uint64_t(a)*1321528399ULL)>>34)*13 |