6

You are given a number, $A$, and you have to determine a number, $B$, such that $B>A$ and the number of $1's$ in the binary representation of $A =$ number of $1's$ in the binary representation of $B$.

What is the smallest $B$?

3 Answers3

15

If $A=0$, there is no such $B$. So let's assume that $A>0$.

Then the binary representation of $A$ is

$$A=Y01XO$$

where $Y$ is a series of digits, perhaps empty, $X$ is a series of $1$'s, perhaps empty, and $O$ is a series of $0$'s, perhaps empty. We can always find such a representation for positive $A$, though that may mean adding a $0$ to the front.

Then your answer is

$$B=Y10OX$$

Here is an example: If $A=011100$, then $B=100011$.


Here is a formula for the answer: Let $n$ be the largest integer such that $2^n \mid A$, and $m$ be the largest integer such that $2^m \mid (A+2^n)$. (In other words, if we say that the rightmost bit is position zero, the one before that one, and so on, then $n$ is the position of the rightmost $1$ in $A$'s binary expansion, while $m$ is the position of the rightmost zero up to position $n+1$. In the binary representation for $A$ above, $O$ has $n$ digits and $X$ has $m-n-1$ digits.) Then

$$B=A+2^n+2^{m-n-1}-1$$

Following through with @ccorn's comment, we can calculate this in C using C's bitwise and operator & if the computer uses two's complement arithmetic:

P2n = A & -A;
P2m = (A+P2n) & -(A+P2n);
B = A + P2n + (P2m / P2n) / 2 - 1;

I'm not sure what happens when $A$ has no next number. My guess is that $B$ is smallest of all numbers with that many $1$ bits.

Barry
  • 2,268
Rory Daulton
  • 32,288
  • 2
    And if bitwise and is available such as C's &, and two's-complement arithmetic is used (as guaranteed for C's unsigned types) then $2^n$ can be obtained as A & -A. – ccorn May 30 '15 at 16:43
  • That's a great idea. But won't the compiler complain about taking the additive inverse of an unsigned number? – Rory Daulton May 30 '15 at 20:39
  • No, because unsigned arithmetic is defined as being done $\bmod{2^N}$ where $N$ is the number of bits in that unsigned type. In fact, the representation of negative values in signed types is not ultimately defined in the ISO/ANSI 9899 standard (it allows one's complement or sign-magnitude for those as well), although you will a hard time finding machines where signed and unsigned arithmetic is done differently. The takeaway from that is that bit operations, including shifts, should be done only with nonnegative signed or with unsigned values. – ccorn May 30 '15 at 20:49
  • If $A=0$, then P2n and P2m will both be zero, giving you a 0/0 which leads to undefined behavior in C (but that case should be excluded anyway, as you did in the beginning). – ccorn May 30 '15 at 21:15
  • If $A\equiv-2^n$ in unsigned semantics, i.e. all ones are already at the left end, which means that no next number is representable, then P2n is $2^n$ and P2m=0, resulting in $B\equiv-1$, i.e. all ones. – ccorn May 30 '15 at 21:53
4

This problem actually shows up in the list of bit twiddling hacks as Next Permutation.

In C++:

t = A | (A - 1);
B = (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(A) + 1)); 

__builtin_ctz(A) is the number of trailing zeros of A, or the largest power of 2 that divides A.

Going through the example in Rory's answer, if A == 011100, then:

t = A | (A - 1) = 011100 | 011011 = 011111

B = (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(A) + 1))
  = (100000) | (((11111111 11100000 & 00000000 00100000) - 1) >> (2 + 1))
  = (100000) | (((100000 - 1) >> 3))
  = (100000) | (11111 >> 3)
  = (100000) | (11)
  = 100011

As a bit of explanation. Let's consider that A looks like:

X0[..1..][..0..]
     p      q

Where X are arbitrary bits followed by a 0, p 1s, and q 0s, where p > 0 but q doesn't have to be (in the original example, X is empty, p is 3, and q is 2). Given that, t is:

             t = X0[..1..][..1..]   // turn on all trailing bits of A
                      p      q

           t+1 = X1[..0..][..0..]
                      p      q

            ~t = Y1[..0..][..0..]  // where Y = ~X
                      p      q

    (~t & -~t) =  1[..0..][..0..]  // "freeze" the right-most 1-bit of ~t
                      p      q

(~t & -~t) - 1 =  0[..1..][..1..]
                      p      q

So when we rightshift that by __builtin_ctz(A) + 1, which is q+1:

((~t & -~t) - 1) >> (q + 1)
               =  [..1..]
                    p-1

Which, when |ed with `t+1:

             B = X1[..0..][..1..]
                     q+1    p-1

Which definitely solves the problem, given that we started with:

             A = X0[..1..][..0..]
                      p      q
Barry
  • 2,268
  • +1 I love bit hacks, I wish someone can come up with an math explanation why this works. – achille hui May 30 '15 at 21:47
  • @achillehui Did my best. Don't know how to format that nicely... hopefully the explanation makes sense. – Barry May 30 '15 at 22:00
  • @achillehui Right-most bit which is 1, but yeah, added that. – Barry May 30 '15 at 22:18
  • oops, you are right, the rightmost one. – achille hui May 30 '15 at 22:21
  • Some remarks: A should be an unsigned type (this guarantees two's-complement arithmetic and avoids out-of-range errors, although most platforms behave the same with signed types); furthermore -~t is a fancy way of writing t+1; and the result of >> is undefined if the shift count reaches the data type's width; for defined results one should write that as >> __builtin_ctz(A) >> 1. – ccorn May 30 '15 at 22:35
  • @ccorn -~t makes it clearer that you're doing z & -z, which wouldn't be as apparent from (~t & (t+1)). For the >>, sort of a moot point since it'll only be undefined when there is no B of the same data type. Not sure it matters if you get 0 back or UB, neither make any sense. – Barry May 30 '15 at 22:43
0

Rewrite A as a binary signal ( a sequence of numbers in the set {0,1} ). Then perform a convolution with [1,-1]. The bits involved in the rightmost convolution which equates to -1 should be permuted with each other. This is to ensure the lowest value bit is switched to the lowest possible value upper bit. However we still need to minimize the remaining bits, the only way to do this is to count the number of 1s which are less significant than said switch bit and to put them at the lsb positions.

example 1: A = 101, conv(A,[1,-1],'valid') = 1,-1 B = 1(10) - bits in paren switched

For example, (as mentioned by Michael): 1(01)10 -> 1(10)01


To expand on ccorns discussion on C implementation, the above can be achieved as ((A>>1) & ~A) and count how many times we need to shift right for the lsb 1 to drop out. In the implementation we can add up the numbers of 1s in the low significant position as we go along with the shifting process above. Then we can just and (&) A by 0 for those positions and or (|) by $( (1 < cnt) - 1)$ which will be the trail of ones where cnt is the number of em.

mathreadler
  • 25,824
  • 1
    As noted by Rory, 10110 should go to 1(10)01, not 1(10)10 - all the 1s after the swap should go to the end. – Empy2 May 30 '15 at 17:34
  • Yep of course you're right. Would have been found out if I had such an example. It can be included in the C implementation above, counting the number of 1:s in A being shifted out while doing the shifts. – mathreadler May 30 '15 at 18:12