简体   繁体   中英

Modulo 7 on 64 bit integer using shift and add (32 bit works but 64 doesn't)

I have a working implementation to calculate modulo 7 of a 32 bit unsigned int but I'm having trouble with the 64 bit implementation. The 32 bit implementations were from this blog post (with a few bug fixes). I was able to get 64 bit versions working for modulo 3, 5, 15, and 6 but not 7. The math is a little over my head.

For reference, here is a gist with the full code .

Here's the working 32 bit:

static public uint Mersenne7(uint a)
{
    a = (a >> 24) + (a & 0xFFFFFF); // sum base 2**24 digits
    a = (a >> 12) + (a & 0xFFF);    // sum base 2**12 digits
    a = (a >> 6) + (a & 0x3F);      // sum base 2**6 digits
    a = (a >> 3) + (a & 0x7);       // sum base 2**2 digits
    a = (a >> 2) + (a & 0x7);       // sum base 2**2 digits
    if (a > 5) a = a - 6;
    return a;
}

I made what seemed like the obvious extension, which worked for modulo 3, 5, and 15, but for mod 7 the results are all over the place with no obvious pattern (except the results all are under 7):

static public ulong Mersenne7(ulong a)
{
    a = (a >> 48) + (a & 0xFFFFFFFFFFFF); // sum base 2**48 digits
    a = (a >> 24) + (a & 0xFFFFFF); // sum base 2**24 digits
    a = (a >> 12) + (a & 0xFFF);    // sum base 2**12 digits
    a = (a >> 6) + (a & 0x3F);      // sum base 2**6 digits
    a = (a >> 3) + (a & 0x7);       // sum base 2**2 digits
    a = (a >> 2) + (a & 0x7);       // sum base 2**2 digits
    if (a > 5) a = a - 6;
    return a;
}

The same technique for 64 bits obviously doesn't work for mod 7. I've been trying some variations but I don't get anything noticeably better and I'm not sure how to work through it systematically.

模7的测试结果

I have benchmarked and shown that calculating modulo using shift and add for Mersenne numbers is faster than the built in modulus operator in my environment, and this is running in a tight loop in a hot path (index to a static size circular buffer). These lower value divisors are also more common than larger buffer sizes.

生活环境基准

The maths behind this is actually pretty simple.

(Note for the maths part I'm using a^b to mean "a to the power b" not "a xor b". These math parts are not supposed to be C# code)

The key trick is that you split a into two pieces so that

a = b * 2^3 + c

where b = a / 2^3 = a >> 3 and c = a mod 2^3 = a & 0x7

Then

a mod 7 = ((b mod 7) * (2^3 mod 7) + c ) mod 7

but 2^3 mod 7 = 1 so

a mod 7 = ( b mod 7 + c ) mod 7 = (b + c) mod 7

We apply this trick several times using

1 = 2^3 mod 7 = 2^6 mod 7 = 2^12 mod 7 = 2^24 mod 7 = 2^48 mod 7

With this in mind it looks like your "working" Mersene7 doesn't work.

I think this:

static public uint Mersenne7(uint a)
{
    a = (a >> 24) + (a & 0xFFFFFF); // sum base 2**24 digits
    a = (a >> 12) + (a & 0xFFF);    // sum base 2**12 digits
    a = (a >> 6) + (a & 0x3F);      // sum base 2**6 digits
    a = (a >> 3) + (a & 0x7);       // sum base 2**2 digits
    a = (a >> 2) + (a & 0x7);       // sum base 2**2 digits
    if (a > 5) a = a - 6;
    return a;
}

should be

static public uint Mersenne7(uint a)
{
    a = (a >> 24) + (a & 0xFFFFFF); // sum base 2**24 digits
    a = (a >> 12) + (a & 0xFFF);    // sum base 2**12 digits
    a = (a >> 6) + (a & 0x3F);      // sum base 2**6 digits
    a = (a >> 3) + (a & 0x7);       // sum base 2**3 digits
    a = (a >> 3) + (a & 0x7);       // sum base 2**3 digits
    if (a >= 7) a = a - 7;
    return a;
}

Note the change in the value in the final comparison, and the removal of the final sum line.

With these changes both the unit and ulong versions should produce correct results I think. (Haven't tested though)

I've duplicated the second contraction - I'm not sure if it is actually needed. (It is to handle overflow - but that may not occur you'll need to try some values to check)

In the ulong case you will need the a=(a>>48) + a & 0xFFFFFFFFFFFFL line like you have already implemented.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM