Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bit twiddling for checking whether a number is in particular range

I found some interesting bit twiddling in "source\common\unicode\utf.h" file of ICU library (International Components for Unicode). The bit twiddling is intended for checking whether a number is in a particular range.

// Is a code point in a range of U+d800..U+dbff?
#define U_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)

I have figured out the magic number (0xfffffc00) come from:

MagicNumber = 0xffffffff - (HighBound - LowBound)

However, I also found that the formula doesn't apply to every arbitrary range. Does somebody here know in what circumstance the formula works?

Is there another bit twiddling for checking whether a number is in particular range?

like image 438
Astaroth Avatar asked Jan 01 '11 10:01

Astaroth


People also ask

What is bit twiddling function?

Bit-twiddling version: boolean isPowerOf2(int x) { return x > 0 && (x & (x - 1)) == 0; } This function returns true if x == 1, 2, 4, 8, 16, ..., 1073741824 but false otherwise. To start, the condition x > 0 excludes numbers that cannot possibly be a positive integral power of 2.

What is Bitwise and of numbers range?

A simple solution is to traverse all numbers from x to y and do bit-wise and of all numbers in range. An efficient solution is to follow following steps. 1) Find position of Most Significant Bit (MSB) in both numbers.

What is toggling a bit?

Toggling a bit means that if the N-th bit is 1, then change it to 0 and if it is 0 then change it to 1. Bitwise XOR ( ^ ) operator used to toggle the bit of an integral data type. To toggle the nth bit shift the '1' nth position toward the left and “XOR” it.


2 Answers

For these tricks to apply, the numbers must have some common features in their binary representation.

0xD800 == 0b1101_1000_0000_0000
0xDBFF == 0b1101_1011_1111_1111

What this test really does is to mask out the lower ten bits. This is usually written as

onlyHighBits = x & ~0x03FF

After this operation ("and not") the lower ten bits of onlyHighBits are guaranteed to be zero. That means that if this number equals the lower range of the interval now, it has been somewhere in the interval before.

This trick works in all cases where the lower and the higher limit of the interval start with the same digits in binary, and at some point the lower limit has only zeroes while the higher limit has only ones. In your example this is at the tenth position from the right.

like image 124
Roland Illig Avatar answered Oct 21 '22 13:10

Roland Illig


If you do not have 2^x boundaries type might use the following trick:

if x >= 0 and x < N you can check both by:

  if Longword( x ) < Longword( N ) then ...

This works due to the fact that negative numbers in signed numbers correspond to the largest numbers in unsigned datatypes.

You could extend this (when range checking is DISABLED) to:

  if Longword( x - A ) < Longword ( ( B - A ) ) then ...

Now you have both tests (range [ A, B >) in a SUB and a CMP plus a single Jcc, assuming (B - A ) is precalculated.

I only use these kind of optimizations when really needed; eg they tend to make your code less readable and it only shaves off a few clock cycles per test.

Note to C like language readers: Longword is Delphi's unsigned 32bit datatype.

like image 22
Ritsaert Hornstra Avatar answered Oct 21 '22 12:10

Ritsaert Hornstra