Lomont.org

(Also lomonster.com and clomont.com)

Efficient divisibility testing

Published

Here’s bit tricks for efficient divisibility testing.

Efficient divisibility testing

The example

Here is a low computational cost method to test if an integer $x$ is divisible by another integer $d$, useful in C-like languages (assembly included). It replaces a possibly costly modulus % operation with a usually lower cost multiplication *.

Here is an example illustrating the method for divisibility by 5:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
uint32_t x = ...
// common method
if ((x%5) == 0)
{
   // do something
}

// cheaper method, completely equivalent
if (x * 3435973837U <= 858993459U)
{
   \\ do something
}

What trickery is this? How does it work? Where do the constants 3435973837U and 858993459U come from?

Note the magic numbers depend on the type of $x$. The above example requires $x$ is an unsigned 32 bit integer, and the language has multiplication overflow computed modulus 32. Many common languages (C,C++,C#,Java, ..) do this.

The values

Before giving the details, here is a table of the magic constants for divisibility testing of odd integers from 3 to 101 inclusive. The bitsize is the size of the unsigned integer $x$, and the test is then x*p <= q.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
| d   |16-bit p|16-bit q| 32-bit p  | 32-bit q  |          64-bit p   |            64-bit q |  
|----:|--------|--------|----------:|----------:|--------------------:|--------------------:|
|    3| 43691  | 21845  | 2863311531| 1431655765| 12297829382473034411|  6148914691236517205|
|    5| 52429  | 13107  | 3435973837|  858993459| 14757395258967641293|  3689348814741910323|
|    7| 28087  |  9362  | 3067833783|  613566756|  7905747460161236407|  2635249153387078802|
|    9| 36409  |  7281  |  954437177|  477218588| 10248191152060862009|  2049638230412172401|
|   11| 35747  |  5957  | 3123612579|  390451572|  3353953467947191203|  1676976733973595601|
|   13| 20165  |  5041  | 3303820997|  330382099|  5675921253449092805|  1418980313362273201|
|   15| 61167  |  4369  | 4008636143|  286331153| 17216961135462248175|  1229782938247303441|
|   17| 61681  |  3855  | 4042322161|  252645135| 17361641481138401521|  1085102592571150095|
|   19| 51739  |  3449  |  678152731|  226050910|  9708812670373448219|   970881267037344821|
|   21| 53053  |  3120  | 1022611261|  204522252| 14933078535860113213|   878416384462359600|
|   23| 14247  |  2849  | 3921491879|  186737708| 15238614669586151335|   802032351030850070|
|   25| 23593  |  2621  | 3264175145|  171798691| 10330176681277348905|   737869762948382064|
|   27| 55827  |  2427  | 1749801491|  159072862|  9564978408590137875|   683212743470724133|
|   29| 49717  |  2259  | 1332920885|  148102320|  3816567739388183093|   636094623231363848|
|   31| 31711  |  2114  | 3186588639|  138547332| 17256631552825064415|   595056260442243600|
|   33| 33761  |  1985  | 1041204193|  130150524|  1117984489315730401|   558992244657865200|
|   35| 44939  |  1872  | 2331553675|  122713351| 12649195936257978251|   527049830677415760|
|   37|  7085  |  1771  | 2437684141|  116080197|  1495681951922396077|   498560650640798692|
|   39| 28567  |  1680  | 2532929431|  110127366|  8040888442386214807|   472993437787424400|
|   41| 39961  |  1598  | 3247414297|  104755299| 10348173504763894809|   449920587163647600|
|   43| 48771  |  1524  |  799063683|   99882960|  9437869060967677571|   428994048225803525|
|   45| 20389  |  1456  | 2767867813|   95443717|  5738987045154082725|   409927646082434480|
|   47| 18127  |  1394  | 1736263375|   91382282|  5887258746928580303|   392483916461905353|
|   49| 22737  |  1337  |  438261969|   87652393|  9035139954469984465|   376464164769582686|
|   51| 64251  |  1285  | 4210752251|   84215045| 18085043209519168251|   361700864190383365|
|   53| 21021  |  1236  | 2350076445|   81037118|  2436362424829563421|   348051774975651917|
|   55| 46471  |  1191  | 1483715975|   78090314|  8049488323073258887|   335395346794719120|
|   57| 60937  |  1149  | 3089362441|   75350303|  9385185581360999945|   323627089012448273|
|   59| 55539  |  1110  | 2693454067|   72796055| 14694863923124558067|   312656679215416129|
|   61| 38677  |  1074  | 3238827797|   70409299|  5745707170499696405|   302405640552615600|
|   63| 61375  |  1040  | 3204181951|   68174084| 17275522227759738815|   292805461487453200|
|   65|  4033  |  1008  | 3237744577|   66076419|  1135184250689818561|   283796062672454640|
|   67| 19563  |   978  |  128207979|   64103989| 17345445920055250027|   275324538413575397|
|   69|  4749  |   949  | 2738819725|   62245902| 17377367605668418189|   267344117010283356|
|   71| 43383  |   923  | 3811027319|   60492497|  1818693077689674103|   259813296812810586|
|   73| 61945  |   897  | 3353604601|   58835168|  9097024474706080249|   252695124297391118|
|   75| 51555  |   873  | 2519714147|   57266230|  3443392227092449635|   245956587649460688|
|   77| 14469  |   851  | 1059797125|   55778796|  5749634516480899205|   239568104853370800|
|   79|  5807  |   829  | 1631000239|   54366674| 11208148297950107311|   233503089540627235|
|   81| 18609  |   809  | 2014922929|   53024287|  3188326136196712625|   227737581156908044|
|   83| 17371  |   789  |  724452315|   51746593| 11779246215742243803|   222249928598910260|
|   85| 64765  |   771  | 4244438269|   50529027| 18229723555195321597|   217020518514230019|
|   87| 60263  |   753  | 1875962727|   49367440|  7421103937699244903|   212031541077121282|
|   89| 18409  |   736  | 4198451177|   48258059| 17617676924329347049|   207266787345051141|
|   91| 12243  |   720  | 3539808211|   47197442|  3446095046736949203|   202711473337467600|
|   93| 54261  |   704  | 1062196213|   46182444|  5752210517608354805|   198352086814081200|
|   95| 23455  |   689  | 3571604383|   45210182|  5631111348816599967|   194176253407468964|
|   97| 41889  |   675  | 1594008481|   44278013| 11790702397628785569|   190172619316593315|
|   99| 33099  |   661  | 3210379595|   43383508| 12670490878911611211|   186330748219288400|
|  101| 45421  |   648  | 2083697005|   42524428|  4200743699953660269|   182641030432767837|

This table is generated by the Mathematica code

1
2
divPair[d_, n_] := {Mod[ExtendedGCD[d, 2^n][[2, 1]], 2^n],Floor[(2^n)/d]};
Table[Flatten[{n, divPair[n, 16], divPair[n, 32], divPair[n, 64]}], {n, 3, 101, 2}] 

The method

Here is how it works, and how you can compute your own values.

Suppose $x$ is an $n$-bit unsigned integer, and write $N=2^n$. Then for any odd integer divisor $d < N$ there is always an integer $p$ depending on $d$ (called a multiplicative inverse mod $N$) so that $pd$ is one more than a multiple of $N$, i.e., $pd=1 + N k$ for some positive integer $k$. This $p$ can be found via the Extended Euclidean algorithm for computing a GCD [1].

The value $q$ to compare against is computed as $q=\lfloor N/d \rfloor$, where $\lfloor y \rfloor$ is the floor function (largest integer less than or equal to $y$).

Ok, so those are the values to use. How does it work? Here is the rough idea, then a proof.

The idea

In the ring of integers mod $N$, multiplying by $p$ acts like dividing by $d$, since for any integer $x$, $(xp)d\equiv x(pd)\equiv x (1)\equiv x$ mod $N$. So think of $xp$ as $x/d$ mod $N$.

The comparison value is the value $N/d$, taken again in the ring of integers mod $N$. The multiplication by $p$ “shuffles” the integers in the ring, so those divisible by $d$ are ordered first, then those with “residue” 1, then those with residue 2, etc. It’s weird, but it works.

The proof

Here is a proof of why it works. Write $\left[t\right]$ to treat the integer $t$ mod $N$ as an integer again for comparison purposes. We need to show $d$ divides $x$ if and only if $[x\cdot p]\leq q$, with $p$ and $q$ as above.

Let $b$ be the remainder of $xp$ divided by $N$, i.e., there is an integer $a$ and an integer integer $0\leq b<N$, with $xp=Na+b$. Thus $[xp] = b$.

Assume $d$ divides $x$ (i.e., $x= t d$ for some integer $t$). Then $[xp]=[tdp]=[t]=t$, and $x<N$ implies $t<N/d$ implies $t\leq q = \lfloor N/d\rfloor$. Thus $[xp]\leq q$ as required.

Conversely, suppose $[xp]\leq q$. Then $xp=Na+b$ implies (expanding two ways) $xpd = x(1+Nk)=x+Nkx$ and $xpd=(Na+b)d =bd + Nad$. Thus $x+Nkx = bd + Nad$. But $b=[xp]\leq q$ implies $bd\leq qd = \lfloor N/d/rfloor d < N$. The strict inequality follows from $N$ and $d$ being relatively prime. Thus, since $0\leq bd < N$, taking both sides of the double expansion mod $N$, we get $x=bd$.

Q.E.D.

The end

This can be extended to divisibility testing against any $d$ (odd or even) by first testing $x$ against the largest power of 2 dividing $d$, then shifting that out if it passed and testing the odd part.

[1] https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm

Categories: Software Math

Tags: Software C++ Math

Comments

Comment is disabled to avoid unwanted discussions from 'localhost:1313' on your Disqus account...