Is there a bit-wise trick for checking the divisibility of a number by 2 or 3?

2024/10/8 4:26:39

I am looking for a bit-wise test equivalent to (num%2) == 0 || (num%3) == 0.

I can replace num%2 with num&1, but I'm still stuck with num%3 and with the logical-or.

This expression is also equivalent to (num%2)*(num%3) == 0, but I'm not sure how that helps.

Answer

Yes, though it's not very pretty, you can do something analogous to the old "sum all the decimal digits until you have only one left" trick to test if a number is divisible by 9, except in binary and with divisibility by 3. You can use the same principle for other numbers as well, but many combinations of base/divisor introduce annoying scaling factors so you're not just summing digits anymore.

Anyway, 16n-1 is divisible by 3, so you can use radix 16, that is, sum the nibbles. Then you're left with one nibble (well, 5 bits really), and you can just look that up. So for example in C# (slightly tested) edit: brute-force tested, definitely works

static bool IsMultipleOf3(uint x)
{const uint lookuptable = 0x49249249;uint t = (x & 0x0F0F0F0F) + ((x & 0xF0F0F0F0) >> 4);t = (t & 0x00FF00FF) + ((t & 0xFF00FF00) >> 8);t = (t & 0x000000FF) + ((t & 0x00FF0000) >> 16);t = (t & 0xF) + ((t & 0xF0) >> 4);return ((lookuptable >> (int)t) & 1) != 0;
}

The trick from my comment, x * 0xaaaaaaab <= 0x55555555, works through a modular multiplicative inverse trick. 0xaaaaaaab * 3 = 1 mod 232, which means that 0xaaaaaaab * x = x / 3 if and only if
x % 3 = 0. "if" because 0xaaaaaaab * 3 * y = y (because 1 * y = y), so if x is of the form
3 * y then it will map back to y. "only if" because no two inputs are mapped to the same output, so everything not divisible by 3 will map to something higher than the highest thing you can get by dividing anything by 3 (which is 0xFFFFFFFF / 3 = 0x55555555).

You can read more about this (including the more general form, which includes a rotation) in Division by Invariant Integers using Multiplication (T. Granlund and P. L. Montgomery).

You compiler may not know this trick. For example this:

uint32_t foo(uint32_t x)
{return x % 3 == 0;
}

Becomes, on Clang 3.4.1 for x64,

movl    %edi, %eax
movl    $2863311531, %ecx       # imm = 0xAAAAAAAB
imulq   %rax, %rcx
shrq    $33, %rcx
leal    (%rcx,%rcx,2), %eax
cmpl    %eax, %edi
sete    %al
movzbl  %al, %eax
ret

G++ 4.8:

mov eax, edi
mov edx, -1431655765
mul edx
shr edx
lea eax, [rdx+rdx*2]
cmp edi, eax
sete    al
movzx   eax, al
ret

What it should be:

imul eax, edi, 0xaaaaaaab
cmp eax, 0x55555555
setbe al
movzx eax, al
ret
https://en.xdnf.cn/q/70157.html

Related Q&A

Check image urls using python-markdown

On a website Im creating Im using Python-Markdown to format news posts. To avoid issues with dead links and HTTP-content-on-HTTPS-page problems Im requiring editors to upload all images to the site and…

How to unittest command line arguments?

I am trying to supply command line arguments to Python unittest and facing some issues. I have searched on internet and found a way to supply arguments asunittest.main(argv=[myArg])The issue is this wo…

different foreground colors for each line in wxPython wxTextCtrl

I have a multilinewx.TextCtrl()object which I set its forground and Background colors for writing strings.I need to write different lines with different colors ,wx.TextCtrl.setForgroundcolor()changes a…

Access deprecated attribute validation_data in tf.keras.callbacks.Callback

I decided to switch from keras to tf.keras (as recommended here). Therefore I installed tf.__version__=2.0.0 and tf.keras.__version__=2.2.4-tf. In an older version of my code (using some older Tensorfl…

How to unpickle a file that has been hosted in a web URL in python

The normal way to pickle and unpickle an object is as follows:Pickle an object:import cloudpickle as cpcp.dump(objects, open("picklefile.pkl", wb))UnPickle an object: (load the pickled file):…

Control tick-labels from multi-level FactorRange

Ive got a three-level bokeh.models.FactorRange which I use to draw tick labels on a vbar-plot. The problem is that there are dozens of factors in total and the lowest-level labels get very cramped.I ca…

PyTorch torch_sparse installation without CUDA

I am new in PyTorch and I have faced one issue, namely I cannot get my torch_sparse module properly installed. In general, I wanted to use module torch_geometric - this I have installed. However, when …

Escaping XPath literal with Python

Im writing a common library to setup an automation test suite with Selenium 2.0 Pythons webdriver.def verify_error_message_present(self, message):try:self.driver.find_element_by_xpath("//span[@cla…

How to return two values in cython cdef without gil (nogil)

I have a function and I am trying to return a number and a vector of ints. What I have is cdef func() nogil:cdef vector[int] vectcdef int a_number...return a_number, vectbut this will give errors like …

Alias for a chain of commands

I have a tool with commands: step1, step2 and step3.I can chain them by calling:$ tool step1 step2 step3I would like to have an alias named all to run all the steps by calling:$ tool allI have found a …