Fast divisibility tests (by 2,3,4,5,.., 16)?

后端 未结 16 2150
轻奢々
轻奢々 2020-12-05 00:14

What are the fastest divisibility tests? Say, given a little-endian architecture and a 32-bit signed integer: how to calculate very fast that a number is divisible by 2,3,4,

16条回答
  •  南方客
    南方客 (楼主)
    2020-12-05 00:53

    As @James mentioned, let the compiler simplify it for you. If n is a constant, any descent compiler is able to recognize the pattern and change it to a more efficient equivalent.

    For example, the code

    #include 
    
    int main() {
        size_t x;
        scanf("%u\n", &x);
        __asm__ volatile ("nop;nop;nop;nop;nop;");
        const char* volatile foo = (x%3 == 0) ? "yes" : "no";
        __asm__ volatile ("nop;nop;nop;nop;nop;");
        printf("%s\n", foo);
        return 0;
    }
    

    compiled with g++-4.5 -O3, the relevant part of x%3 == 0 will become

    mov    rcx,QWORD PTR [rbp-0x8]   # rbp-0x8 = &x
    mov    rdx,0xaaaaaaaaaaaaaaab
    mov    rax,rcx
    mul    rdx
    lea    rax,"yes"
    shr    rdx,1
    lea    rdx,[rdx+rdx*2]
    cmp    rcx,rdx
    lea    rdx,"no"
    cmovne rax,rdx
    mov    QWORD PTR [rbp-0x10],rax
    

    which, translated back to C code, means

    (hi64bit(x * 0xaaaaaaaaaaaaaaab) / 2) * 3 == x ? "yes" : "no"
    // equivalatent to:                 x % 3 == 0 ? "yes" : "no"
    

    no division involved here. (Note that 0xaaaaaaaaaaaaaaab == 0x20000000000000001L/3)


    Edit:

    • The magic constant 0xaaaaaaaaaaaaaaab can be computed in http://www.hackersdelight.org/magic.htm
    • For divisors of the form 2n - 1, check http://graphics.stanford.edu/~seander/bithacks.html#ModulusDivision

提交回复
热议问题