5

Is there an efficient way to remove the first bit of a number in C++ / Python, assuming you don't know how large the number is or its datatype?

I know in Python I can do it by getting the bin(n), truncating the string by 1, and then recasting it to an int, but I am curious if there is a more "mathematical" way to do this.

e.g. say the number is 6, which is 110 in binary. Chop the first bit and it becomes 10, or 2.

user111373
  • 125
  • 1
  • 3
  • 8
  • what's the "first bit"? most significant? least significant? If you know nothing about the size of the number or it's format, you'll probably trash the number completely. e.g. remove the most sig fig of a signed number and you've simply removed the sign bit. how do you handle an 8bit number v.s. a 16bit number? if it's 16bit and you remove bit 7,b ecause you thought it was an 8bit number, now you've trashed the value completely. – Marc B Nov 25 '13 at 18:19
  • I don't know what most/least significant means but I added an example. I assume leftmost bit of value 1 is "most" significant, rightmost bit of value 1 is "least" significant – user111373 Nov 25 '13 at 18:20
  • In C++, you might consider the [bit shift operations](http://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Companion/cxx_crib/shift.html). – cm2 Nov 25 '13 at 18:22
  • How did you get 10 from 6? What bit was changed? – Vlad from Moscow Nov 25 '13 at 18:22
  • 3
    @cm2 -- bit shifting (and bit operations in general) works in python too for integers – mgilson Nov 25 '13 at 18:22
  • @mgilson good to know -- I never do these sorts of operations... :) – cm2 Nov 25 '13 at 18:27

5 Answers5

7

There's a bit twiddling hack to remove a bit at a time until only the uppermost is left:

def upper_bit(x):
    while x & (x - 1):
        x &= x - 1
    return x

Now you can use that as a mask:

def mask_off(x, mask):
    return x & ~mask

>>> mask_off(6, upper_bit(6))
2

Note that this only works for positive numbers, because of the boundless nature of Python ints.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
5

looking at 110 (6 decimal)

The Most Significant bit is 100 (4 decimal) // -- Note that this is always a power of 2

Create a mask: one less than the MSB is 011 (3 decimal)

Mask off the highest bit using bitwise-and: 110 & 011 = 10 (2 decimal)

Calculating the MSB (Most Significant Bit) has been handled here and elsewhere quite often

Glenn Teitelbaum
  • 10,108
  • 3
  • 36
  • 80
2

Well, you could create a loop in which you would double some variable (say x) in each iteration and then check whether this variable is greater than your number. If it is, divide it by two and subtract from your number. For example, if your number is 11:

-first iteration: x=1<11, so continue

-second iteration: x =2<11, so continue

-third iteration: x=4<11, so continue

-fourth iteration: x=8<11, so continue

-fifth iteration: x=16>11, so divide x by two: x=8. Then subtract 8 from your number and get answer:

11-8=3.

akrasuski1
  • 820
  • 1
  • 8
  • 25
2

If you using a C compiler that supports __builtin_clz, and you limit yourself to the type that __builtin_clz supports, you can do:

unsigned int chopWithBuiltin(unsigned int x) {
  //get number of leading redundant sign bits,
  //which is one less than the position of the MSB
  int msb_idx = __builtin_clz(x);
  //now make a mask that is all the bits below the MSB
  int mask = UINT_MAX >> (msb_idx+1);
  return x & mask;
}

This uses __builtin_clz which hopefully maps to something fast in assembly instead of a loop to detect the MSB.

For negative numbers you can build something similar with __builtin_clrsb but it gets complicated.

mtrw
  • 34,200
  • 7
  • 63
  • 71
2

First find the length of the binary number by log2(n) logarithm in base 2 of n

n = 6
l = int(log(n, 2)) + 1

As your number is 6 which is 110 in binary find the MSB 100 (4 in decimal).

mask = 2**(l-1) #msb will always be 2^(length-1)

Now simply use XOR operator to remove the MSB

res = n^mask

Code in one line would be

n = 2**int(log(n,2)) ^ n
Anirudh S
  • 21
  • 2