Next Identical Popcount
June 22, 2018
Today’s exercise is an interview question:
The binary weight of a positive integer is the number of 1-bits in its binary representation. For example, the decimal number 7, which is 111 in binary, has a binary weight of 3. The smallest integer greater than 7 that has the same binary weight as 7 is 11, which is 1011 in binary.
Your task is to write a program that, given a positive integer, finds the next larger integer that has the same binary weight. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
Cool drill. Here is my take on it, using Julia.
function FindWeight(x::Int64)
X = bin(x)
c = 0
end
function main(x::Int64)
z = x + 1
w = FindWeight(x)
end
main(7) # outputs 11
main(1) # outputs 2
main(100) # outputs 104
Have a nice weekend everyone!
or slightly longer – but without the sprintf “hack” to get the binary count using & / >> operator
This is just the “next k-subset of 1..n” problem. It is possible to go fairly directly from one popc-k integer to the next. Let the least significant 1
bit be at offset p. If bit(p+1) is 0, set it to 1 and clear bit(p). If bit(p+1)
is 1, clear bit(p), set bit(0), advance bits (p+1..msb) to the next integer
with k-1 bits.
The algorithm at the top of the page is spectacularly inefficient. Consider
the case of 32-bit integers, bit(30) is on, and all the others are off. (k=1)
The (next n) algorithm loops about 2**30 times.
@Richard_OKeefe, for 0b111000, the next number should be 0b1000011. I believe your proposed algorithm would incorrectly return 0b1010001. Please let me know if I’ve misinterpreted.
Assuming 32-bin unsigned integers and supporting wraparound:
unsigned int next_identical_popcount(unsigned int n) {
unsigned short shift = 0;
unsigned int ones = 0;
while (shift < 31) {
if ((n & 3) == 1)
return (((n + 1) << shift) | ones);
if ((n & 1) == 1)
ones = (ones << 1) | 1;
n >>= 1;
shift++;
}
if (n == 1)
ones = (ones << 1) | 1;
return ones;
}
Clojure/Script with arbitrary precision integer.
The solution scans each bit b of the input i consecutively using a bit mask b that it shifts left at each iteration. If i(b) is 1 and i(b+1) is 0, then it sets i(b) to 0 and i(b+1) to 1. If there are only contiguous 1’s until the msb, then it shifts left the msb by 1 and or’s it with the remaining bits kept in lsb position (lsbits).
Test:
cljs.user=> (next-weight 7)
11
cljs.user=> (next-weight 15)
23
cljs.user=> (next-weight 23)
27
cljs.user=> (next-weight 56)
67
Here’s a solution in C.
y has the rightmost bit of x. z has the rightmost group of bits from x turned off, and the neighbor bit to the left turned on. The output or’s z with x’s rightmost group of bits shifted to the right 1 place past the end (i.e., 1 bit truncated).
Example:
Here’s the same approach I posted above, but using GCC’s intrinsic __builtin_ffs to shift the group of 1s instead of division.
Here’s a port to Python, which works on arbitrary sized integers.
My earlier code has a mistake. The mask was intended to be ~(x & z) – 1. Alternatively, a mask of x ^ z makes sense too.
Coincidentally the mask I used doesn’t affect the result, since relevant bit ends up getting removed in the next step (but I wasn’t intending for it to work this way).
Here are the updates.
A Haskell version.
Oops. Shouldn’t have put those angle brackets in the “no next snob” string. Having removed them from the code, here’s what the output looks like.
@Globules: I was about to say “this is in HAKMEM!”, but you beat me to it. Link: http://home.pipeline.com/~hbaker1/hakmem/hacks.html#item175, I’d guess that is PDP-8 or 11 assembler.
@Globules: and using popcount (which these days will be a single instruction) is a nice optimization over the original.
A solution in racket:
Testing:
Here’s a solution in Python that operates on a string representation of the binary number. It finds the last group of ones, then swaps a one from this group with the zero to the left, and moves the remaining ones to the end.
I forgot the import.
In Python.
[…] a comment on the prior exercise, Richard A. O’Keefe […]
A solution in C#, for Linqpad.
void Main()
{
CalculateNextIdenticalPopcount(5);
CalculateNextIdenticalPopcount(7);
CalculateNextIdenticalPopcount(21);
}
int CalculateNextIdenticalPopcount(int input)
{
var bits = input.GetBits(out var bitCount);
var binaryWeight = bits.Count(b => b);
var successorBits = new bool[bitCount+1];
successorBits[bitCount] = true;
for(int i=0;i<binaryWeight-1;i++)
{
successorBits[i] = true;
}
var successor = successorBits.ToInt32();
$"{FormatNumber(input)} => {FormatNumber(successor)}".Dump();
return successor;
}
string FormatNumber(int number)
{
var bits = number.GetBits(out var bitCount);
var builder = new StringBuilder();
builder.Append(number);
builder.Append(" (");
for(int i=bitCount-1;i>=0;i–)
{
builder.Append(bits[i] ? 1 : 0);
}
builder.Append(")");
return builder.ToString();
}
static class BitExtensions
{
public static Int32 ToInt32(this bool[] bits)
{
Int32 number = 0;
for (int i = 0; i < bits.Length; i++)
{
if(bits[i])
{
var mask = (1 << i);
number |= mask;
}
}
return number;
}
public static bool[] GetBits(this Int32 number, out int bitCount)
{
var integerBits = sizeof(Int32) * 8;
var bits = new bool[integerBits];
bitCount = 0;
for (int i = 0; i < integerBits; i++)
{
var mask = (1 << i);
bits[i] = (mask & number) == 0 ? false : true;
if(bits[i])
{
bitCount = i+1;
}
}
return bits;
}
}
import java.util.Scanner;
public class binary_weight
{ public int x=0;
public int bin_wt(int n)
{ int sum=0;
while(n!=0)
{
sum+=n%2;
n/=2;
}
return(sum);
}
void check()
{
Scanner in=new Scanner(System.in);
System.out.println(“Enter the number”);
x=in.nextInt();
for(int i=x+1;i>0;i++)
{
if(bin_wt(x)==bin_wt(i))
{
System.out.println(“The number which has the same binary weight as ” +x+ ” is “+i); break;
}
else
continue;
}
}
public static void main(String args[])
{
binary_weight obj=new binary_weight();
obj.check();
}
}
By the way, Rust has a function that does this call count_ones()
A couple of solutions in Racket.