@ leforban, @ mtylerjr - The idea behind the formula is actually simple.
We want to find n mod 10
Or in the following form: n = 10k+r, 0 <= r <= 9 We want to find: r
Finding a mod of a number that is power of 2 is very trivial and cheap operation, but 10 is not. Let’s take a look at a different function:
16n/10 mod 16
Let’s open it up and simplify:
16(10k+r)/10 mod 16 = (16k + 16r/10) mod 16 = 16r/10 mod 16
Now if we use the possible values of r=[0…9] and calculate 16r/10 mod 16. We will get back 10 distinct values:
0, 1, 3, 4, 6, 8, 9,11, 12, 14 for r = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 respectively.
Back to 16n/10 mod 16. If we find an easy way to compute that function we can easily map it to mod 10 reminder using the above results. We can use an approximation this way: multiply n by b/10[/b] and then divide it by 2^28.
0x19999999 is a floor value of b/10[/b] in hex and division by 2^28 is the same as right shift by 28.
((uint)(n * 0x19999999) >> 28 )
Due to approximation the final values are slightly different and 0 is a special case (n=0 returns 0, all other n where r = 0 return 15), but they are still distinct and can be mapped to mod 10 reminder.
P.S. If we treat the result as an index in a lookup table for the reminder. We can use this table:
mod10reminder[16] = { 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 0};
This whole magic comes from:
Hacker’s Delight (2nd Edition)