Given that x is a set, the following code goes through the subsets of a set x:
int b = 0;
do {
// process subset b
} while (b=(b-x)&x);
I came across this reading about bit manipulation and how it's used to represent sets.
What does the expression b=(b-x)&x mean? How does it work?
I'm familiar with == but not with = being here in the do while loop. How does that work? Does the loop terminate when the value of (b-x)&x becomes zero?
The usage of the code is as follows:
#include <iostream>
using namespace std;
void subsets(int x, int b){
do{
cout << b<<"\n";
}while(b = (b-x)&x);
}
int main()
{
int x = (1<<1)|(1<<3)|(1<<4)|(1<<8);
int b = 0;
subsets(x, b);
return 0;
}
The output given by the above code is:
0
2
8
10
16
18
24
26
256
258
264
266
272
274
280
282
Easy parts first:
Does the loop terminate when the value of (b-x)&x becomes zero? I'm familiar with == but not with = being here in the do while loop. How does that work?
Yes.
A do/while loop like this:
do{
cout << b<<"\n";
}while(b = (b-x)&x);
does the following steps:
Execute cout << b<<"\n";.
Execute b = (b-x)&x and remember the result.
If the result isn't zero, go back to step 1.
= is assignment. It sets a variable to a value, as in i = 0;. But... huh? What's the result of an assignment? In C, the result of an assignment is the value that was assigned. This lets you write a = b = c = 0;, to set three variables a, b and c to 0. This is equivalent to a = (b = (c = 0));, i.e. it sets c to 0, then it sets b to the result of that, then it sets a to the result of that. (In C++ it's possible to write a class which doesn't follow this rule, but we're only dealing with ints here, not classes)
Some people like to use this trick to make their code shorter. You could've written it like this instead:
do{
cout << b<<"\n";
b = (b-x)&x;
}while(b);
What does the expression b=(b-x)&x mean?
= is assignment. - is subtraction. & is "bitwise AND".
This subtracts x from b. Then, it bitwise-ANDs the answer to that with x. Then, it sets b to the answer to that.
What is bitwise AND? Bitwise AND is an operation where you write down the numbers in binary, lines them up, then creates a new number, where each bit is 1 if the bits in both inputs are 1, and 0 otherwise. Example:
01011010 = 90
& 11101000 = 232
-----------------
01001000 = 72
so 90 & 232 is 72.
How does it work?
This program is basically treating the numbers as binary. Each bit in x is 1 to say something is "in the set", or 0 to say that it's not.
b then goes through all the possible combinations of those bits. b = (b-x) & x; is a bit of a "voodoo magic spell" to change the combination to the next one in order, for example:
- 000000000 <- b the first time
011001001 <- x
-----------------
100110111 <- b-x
& 011001001 <- x
-----------------
000000001 <- (b-x)&x (b the second time)
- 011001001 <- x
-----------------
100111000 <- b-x
& 011001001 <- x
-----------------
000001000 <- (b-x)&x (b the third time)
- 011001001 <- x
-----------------
100111111 <- b-x
& 011001001 <- x
-----------------
000001001 <- (b-x)&x (b the fourth time)
...etc...
You can be sure that whoever invented this trick was very clever.
Related
I found this snippet on 'codefights' submitted by a programmer. My solution to the problem was 30 lines, whereas this is just a beauty.
But I am not able to understand the logic.
Can anyone explain this.
int mirrorBits(int a) {
int r = 0;
for (; a; a >>= 1)
r = r << 1 | a & 1;
return r;
}
input a = 8; output : 1
First of all, there is a very good StackOverflow answer here:
Most Efficient Algorithm for Bit Reversal ( from MSB->LSB to LSB->MSB) in C
The algorithm makes use of
>> ... binary shift right (100b >> 1 == 10b)
<< ... binary shift left (100b << 1 == 1000b
| .... binary or (100b | 10b == 110b)
& .... binary and (111b & 100b == 100b)
The for loop shifts a to the right until all bits have fallen out of a.
Imagine you start with a = 101101 then a >>= 1 does the following:
At the end of loop 1: a == 10110
At the end of loop 2: a == 01011
At the end of loop 3: a == 00101
At the end of loop 4: a == 00010
At the end of loop 5: a == 00001
At the end of loop 6: a == 00000 (condition fails -> loop ends)
The body of the loop shifts b one bit right, uses & to mask the last bit of a and adds it as last digit to b. The or can be used to add the last digit because << inserts 0 for all "new" bits.
Imagine you start with a = 101101
loop 1: a = 101101, r = 0 => 01
loop 2: a = 010110, r = 01 => 010
loop 3: a = 001011, r = 010 => 0101
loop 4: a = 000101, r = 0101 => 01011
loop 5: a = 000010, r = 01011 => 010110
loop 6: a = 000001, r = 010110 => 0101101
In detail the inner loop #3 does the following:
(a is 001011 and r is 010)
r << 1 changes r from 010 to 0100. The last digit is the inserted 0.
a & 1 masks the current last bit from a (the 1 in 001011)
now we have (0100 | 1) which has the result 0101.
Warning: This algorithm is not really mirroring the bits, because you do not get the original value if you apply the algorithm to the result.
If you need a mirrored 32-bit unsigned integer you have to loop 32 times independently of the value of a:
unsigned int r = 0;
unsigned int a = 12345;
for(int i = 0; i < 32; ++i)
{
r = (r << 1) | (a & 1);
a >>= 1;
}
If you apply this algorithm twice, you should get the original value.
If I take 3 numbers A B C with 3 digits each (between 100-999) and do :
A + B = C
If all nine digits used are non zero and different from each other ( 1-2-3-4-5-6-7-8-9) then the sum of the digits of C will always be 18.
ex : 152 + 487 = 639 -----> 6+3+9 = 18
357 + 462 = 819 = -----> 8+1+9 = 18
I need my program to show all cases of numbers A,B and C that respect this relation. I am unsure how to tackle this problem. I was thinking of either using an outer for loop and a inner for loop or using the rand function but I am unsure how to give the necessary conditions to any of these methods.
Enumerate all the 9! (=362880) permutations of the 9 digits, then for each permutation check whether it meets the requirements.
1 2 3 4 5 6 7 8 9 one permutation
----- ----- -----
A B C chunked to these numbers (simple base10 math)
For generating the permutations you can use next_permutation.
My approach would be to go through all permutations of "123456789" using std::next_permutation and check that the first 3 digits plus the second 3 digits minus the last 3 digits equals 0. Something like:
int main()
{
std::string numbers = "123456789";
int a, b, c;
do
{
a = std::stoi(numbers.substr(0, 3));
b = std::stoi(numbers.substr(3, 3));
c = std::stoi(numbers.substr(6, 3));
if (a + b == c)
std::cout << a << " + " << b << " = " << c << "\n";
} while (std::next_permutation(numbers.begin(), numbers.end()));
}
Find all 3-digit number pairs whose sums of digits are 18.
Add the numbers; discard if sum not equal to 999.
Discard entries where A1 == B2 and A2 == B1
Optimizations:
There is only one unique number B for each number A such that A + B == 999.
For every number A and B the differcence between the current A and the next A and the current B And the next B is always greater than 8.
Use if conditions for the required mathematic conditions. Simple as that.
Iterate through all the 3-digit number pairs by using a for-loop or paralleize by using async
I'm on mobile so I can't code; I'll edit this if you need more.
You are given a large range [a,b] where 'a' and 'b' can be typically between 1 and 4,000,000,000 inclusive. You have to find out the XOR of all the numbers in the given range.
This problem was used in TopCoder SRM. I saw one of the solutions submitted in the match and I'm not able to figure out how its working.
Could someone help explain the winning solution:
long long f(long long a) {
long long res[] = {a,1,a+1,0};
return res[a%4];
}
long long getXor(long long a, long long b) {
return f(b)^f(a-1);
}
Here, getXor() is the actual function to calculate the xor of all number in the passed range [a,b] and "f()" is a helper function.
This is a pretty clever solution -- it exploits the fact that there is a pattern of results in the running XORs. The f() function calculates the XOR total run from [0, a]. Take a look at this table for 4-bit numbers:
0000 <- 0 [a]
0001 <- 1 [1]
0010 <- 3 [a+1]
0011 <- 0 [0]
0100 <- 4 [a]
0101 <- 1 [1]
0110 <- 7 [a+1]
0111 <- 0 [0]
1000 <- 8 [a]
1001 <- 1 [1]
1010 <- 11 [a+1]
1011 <- 0 [0]
1100 <- 12 [a]
1101 <- 1 [1]
1110 <- 15 [a+1]
1111 <- 0 [0]
Where the first column is the binary representation and then the decimal result and its relation to its index (a) into the XOR list. This happens because all the upper bits cancel and the lowest two bits cycle every 4. So, that's how to arrive at that little lookup table.
Now, consider for a general range of [a,b]. We can use f() to find the XOR for [0,a-1] and [0,b]. Since any value XOR'd with itself is zero, the f(a-1) just cancels out all the values in the XOR run less than a, leaving you with the XOR of the range [a,b].
Adding to FatalError's great answer, the line return f(b)^f(a-1); could be explained better. In short, it's because XOR has these wonderful properties:
It's associative - Place brackets wherever you want
It's commutative - that means you can move the operators around (they can "commute")
Here's both in action:
(a ^ b ^ c) ^ (d ^ e ^ f) = (f ^ e) ^ (d ^ a ^ b) ^ c
It reverses itself
Like this:
a ^ b = c
c ^ a = b
Add and multiply are two examples of other associative/ commutative operators, but they don't reverse themselves. Ok, so, why are these properties important? Well, a simple route is to expand it out into what it really is, and then you can see these properties at work.
First, let's define what we want and call it n:
n = (a ^ a+1 ^ a+2 .. ^ b)
If it helps, think of XOR (^) as if it was an add.
Let's also define the function:
f(b) = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b
b is greater than a, so just by safely dropping in a few extra brackets (which we can because it's associative), we can also say this:
f(b) = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)
Which simplifies to:
f(b) = f(a-1) ^ (a ^ a+1 ^ a+2 .. ^ b)
f(b) = f(a-1) ^ n
Next, we use that reversal property and commutivity to give us the magic line:
n = f(b) ^ f(a-1)
If you've been thinking of XOR like an add, you would've dropped in a subtract there. XOR is to XOR what add is to subtract!
How do I come up with this myself?
Remember the properties of logical operators. Work with them almost like an add or multiply if it helps. It feels unusual that and (&), xor (^) and or (|) are associative, but they are!
Run the naive implementation through first, look for patterns in the output, then start finding rules which confirm the pattern is true. Simplify your implementation even further and repeat. This is probably the route that the original creator took, highlighted by the fact that it's not completely optimal (i.e. use a switch statement rather than an array).
I found out that the below code is also working like the solution given in the question.
May be this is little optimized but its just what I got from observing repetition like given in the accepted answer,
I would like to know / understand the mathematical proof behind the given code, like explained in the answer by #Luke Briggs
Here is that JAVA code
public int findXORofRange(int m, int n) {
int[] patternTracker;
if(m % 2 == 0)
patternTracker = new int[] {n, 1, n^1, 0};
else
patternTracker = new int[] {m, m^n, m-1, (m-1)^n};
return patternTracker[(n-m) % 4];
}
I have solved the problem with recursion. I simply divide the dataset into an almost equal part for every iteration.
public int recursion(int M, int N) {
if (N - M == 1) {
return M ^ N;
} else {
int pivot = this.calculatePivot(M, N);
if (pivot + 1 == N) {
return this.recursion(M, pivot) ^ N;
} else {
return this.recursion(M, pivot) ^ this.recursion(pivot + 1, N);
}
}
}
public int calculatePivot(int M, int N) {
return (M + N) / 2;
}
Let me know your thoughts over the solution. Happy to get improvement feedbacks. The proposed solution calculates the XOR in 0(log N) complexity.
Thank you
To support XOR from 0 to N the code given needed to be modified as below,
int f(int a) {
int []res = {a, 1, a+1, 0};
return res[a % 4];
}
int getXor(int a, int b) {
return f(b) ^ f(a);
}
Adding on even further to FatalError's answer, it's possible to prove (by induction) that the observed pattern in f() will cycle for every 4 numbers.
We're trying to prove that for every integer k >= 0,
f(4k + 1) = 1
f(4k + 2) = 4k + 3
f(4k + 3) = 0
f(4k + 4) = 4k + 4
where f(n) is 1 ^ 2 ^ ... ^ n.
As our base case, we can work out by hand that
f(1) = 1
f(2) = 1 ^ 2 = 3
f(3) = 3 ^ 3 = 0
f(4) = 0 ^ 4 = 4
For our inductive step, assume that these equations are true up to a particular integer 4x (i.e. f(4x) = 4x). We want to show that our equations are true for 4x + 1, 4x + 2, 4x + 3 and 4x + 4.
To help write and visualize the proof, we can let b(x) denote the binary (base-2) string representation of x, for example
b(7) = '111', b(9) = '1001'.
and
b(4x) = 'b(x)00'
b(4x + 1) = 'b(x)01'
b(4x + 2) = 'b(x)10'
b(4x + 3) = 'b(x)11'
Here is the inductive step:
Assume: f(4x) = 4x = 'b(x)00'
Then:
f(4x + 1) = f(4x) ^ (4x + 1) // by definition
= f(4x) ^ 'b(x)01' // by definition
= 'b(x)00' ^ 'b(x)01' // from assumption
= '01' // as b(x) ^ b(x) = 0
f(4x + 2) = f(4x + 1) ^ (4x + 2)
= f(4x + 1) ^ 'b(x)10'
= '01' ^ 'b(x)10'
= 'b(x)11' // this is 4x + 3
f(4x + 3) = f(4x + 2) ^ (4x + 3)
= f(4x + 2) ^ 'b(x)11'
= 'b(x)11' ^ 'b(x)11'
= '00'
For the last case, we don't use binary strings,
since we don't know what b(4x + 4) is.
f(4x + 4) = f(4x + 3) ^ (4x + 4)
= 0 ^ (4x + 4)
= 4x + 4
So the pattern holds for the next four numbers after 4x, completing the proof.
I need to optimize an expression of the form:
(a > b) || (a > c)
I tried several optimized forms one of which is as follows:
(a * 2) > (b + c)
Optimization is not from the compiler's point of view. I would like to reduce the two >s to one.
This is based on the assumption that 1 <= (a, b, c) <= 26
However, this works only for some cases. Is the optimization I am trying to do, really possible? If yes, a start would be really helpful.
The answer is probably: you do not want to optimize that. Moreover, I doubt that there's any way to write this more efficiently. If you say that a, b and c are values between 1 and 26, you shouldn't be using integers (you don't need that precision) if you wanted to be optimal (in size) anyway.
If a > b, the expression a > c will not be executed anyway. So you have at maximum 2 (and at minimum 1) conditional operations, which is really not worth an optimization.
I'm quite doubtful this is even an optimisation in most cases.
a > b || a > c
will evaluate to:
compare a b
jump not greater
compare a c
jump not greater
where
a * 2 > b + c
gives:
shift a left 1 (in temp1)
add b to c (in temp2)
compare temp1 temp2
jump if not greater
As always with performance, it's always much better to base your decision on actual performance measurements (preferably on a selection of processor architectures).
The best I can come up with is this
char a, b, c;
std::cin >> a >> b >> c;
if (((b-a) | (c-a)) & 0x80) {
// a > b || a > c
}
With gcc -O2 this generates only one conditional branch
40072e: 29 c8 sub %ecx,%eax
400730: 29 ca sub %ecx,%edx
400732: 09 d0 or %edx,%eax
400734: a8 80 test $0x80,%al
400736: 74 17 je 40074f <main+0x3f>
This leverages the constraints of the input values, since the values cannot be greater than 26 then subtracting a from b will give you a negative value when a > b, in two's complement you know bit 7 will be set in that case - the same applies to c. I then OR both so that bit 7 indicates whether a > b || a > c, lastly we inspect bit 7 by AND with 0x80 and branch on that.
Update: Out of curiosity I timed 4 different ways of coding this. To generate test data I used a simple linear congruential pseudo-random number generator. I timed it in a loop for 100 million iterations. I assumed for simplicity that if the condition is true we want to add 5 to a counter, do nothing otherwise. I timed it using g++ (GCC) 4.6.3 20120306 (Red Hat 4.6.3-2) on an Intel Xeon X5570 # 2.93GHz using -O2 optimization level.
Here's the code (comment out all but one of the conditional variants):
#include <iostream>
unsigned myrand() {
static unsigned x = 1;
return (x = x * 1664525 + 1013904223);
}
int main() {
size_t count = 0;
for(size_t i=0; i<100000000; ++i ) {
int a = 1 + myrand() % 26;
int b = 1 + myrand() % 26;
int c = 1 + myrand() % 26;
count += 5 & (((b-a) | (c-a)) >> 31); // 0.635 sec
//if (((b-a) | (c-a)) & 0x80) count += 5; // 0.660 sec
//if (a > std::max(b,c)) count += 5; // 0.677 sec
//if ( a > b || a > c) count += 5; // 1.164 sec
}
std::cout << count << std::endl;
return 0;
}
The fastest is a modification on the suggestion in my answer, where we use sign extension to generate a mask that is either 32 1s or 32 0s depending on whether the condition is true of false, and use that to mask the 5 being added so that it either adds 5 or 0. This variation has no branches. The times are in a comment on each line. The slowest was the original expression ( a > b || a > c).
I have two simple while loops in my program that I feel ought to be math equations, but I'm struggling to convert them:
float a = someValue;
int b = someOtherValue;
int c = 0;
while (a <= -b / 2) {
c--;
a += b;
}
while (a >= b / 2) {
c++;
a -= b;
}
This code works as-is, but I feel it could be simplified into math equations. The idea here being that this code is taking an offset (someValue) and adjusting a coordinate (c) to minimize the distance from the center of a tile (of size someOtherValue). Any help would be appreciated.
It can be proved that the following is correct:
c = floor((a+b/2)/b)
a = a - c*b
Note that floor means round down, towards negative infinity: not towards 0. (E.g. floor(-3.1)=-4. The floor() library functions will do this; just be sure not to just cast to int, which will usually round towards 0 instead.)
Presumably b is strictly positive, because otherwise neither loop will never terminate: adding b will not make a larger and subtracting b will not make a smaller. With that assumption, we can prove that the above code works. (And paranoidgeek's code is also almost correct, except that it uses a cast to int instead of floor.)
Clever way of proving it:
The code adds or subtracts multiples of b from a until a is in [-b/2,b/2), which you can view as adding or subtracting integers from a/b until a/b is in [-1/2,1/2), i.e. until (a/b+1/2) (call it x) is in [0,1). As you are only changing it by integers, the value of x does not change mod 1, i.e. it goes to its remainder mod 1, which is x-floor(x). So the effective number of subtractions you make (which is c) is floor(x).
Tedious way of proving it:
At the end of the first loop, the value of c is the negative of the number of times the loop runs, i.e.:
0 if: a > -b/2 <=> a+b/2 > 0
-1 if: -b/2 ≥ a > -3b/2 <=> 0 ≥ a+b/2 > -b <=> 0 ≥ x > -1
-2 if: -3b/2 ≥ a > -5b/2 <=> -b ≥ a+b/2 > -2b <=> -1 ≥ x > -2 etc.,
where x = (a+b/2)/b, so c is: 0 if x>0 and "ceiling(x)-1" otherwise. If the first loop ran at all, then it was ≤ -b/2 just before the last time the loop was executed, so it is ≤ -b/2+b now, i.e. ≤ b/2. According as whether it is exactly b/2 or not (i.e., whether x when you started was exactly a non-positive integer or not), the second loop runs exactly 1 time or 0, and c is either ceiling(x) or ceiling(x)-1. So that solves it for the case when the first loop did run.
If the first loop didn't run, then the value of c at the end of the second loop is:
0 if: a < b/2 <=> a-b/2 < 0
1 if: b/2 ≤ a < 3b/2 <=> 0 ≤ a-b/2 < b <=> 0 ≤ y < 1
2 if: 3b/2 ≤ a < 5b/2 <=> b ≤ a-b/2 < 2b <=> 1 ≤ y < 2, etc.,
where y = (a-b/2)/b, so c is: 0 if y<0 and 1+floor(y) otherwise. [And a now is certainly < b/2 and ≥ -b/2.]
So you can write an expression for c as:
x = (a+b/2)/b
y = (a-b/2)/b
c = (x≤0)*(ceiling(x) - 1 + (x is integer))
+(y≥0)*(1 + floor(y))
Of course, next you notice that (ceiling(x)-1+(x is integer)) is same as floor(x+1)-1 which is floor(x), and that y is actually x-1, so (1+floor(y))=floor(x), and as for the conditionals:
when x≤0, it cannot be that (y≥0), so c is just the first term which is floor(x),
when 0 < x < 1, neither of the conditions holds, so c is 0,
when 1 ≤ x, then only 0≤y, so c is just the second term which is floor(x) again.
So c = floor(x) in all cases.
c = (int)((a - (b / 2)) / b + 1);
a -= c * b;
Test case at http://pastebin.com/m1034e639
I think you want something like this:
c = ((int) a + b / 2 * sign(a)) / b
That should match your loops except for certain cases where b is odd because the range from -b/2 to b/2 is smaller than b when b is odd.
Assuming b is positive, abs(c) = floor((abs(a) - b/2) / b). Then, apply sign of a to c.