How to solve XOR equations like A xor ( A - 4 ) = 5? - bit-manipulation

Actually I an trying to solve "Xoring Ninja" in Hackerrank.
https://www.hackerrank.com/challenges/xoring-ninja/problem
Let A be a set of N elements {a1, a2, ......, aN}
The XORSUM of set A is defined here as the sum of the XOR's of all A's
non-empty subsets.
Let S = XORSUM
S = (a1 + a2 + ... + aN) + [(a1 ^ a2) + (a1 ^ aN) + ..] + {3 sized subsets} + ... + (a1 ^ a2 ^ ..... ^ aN)
Let T = (a1 ^ a2 ^ .... ^ aN)
then S = T ^ (S - T)
S ^ S = S ^ T ^ (S - T)
0 = T ^ S ^ (S - T)
T ^ 0 = T ^ T ^ S ^ (S - T)
T = S ^ (S - T)
I wanted to know how to solve any equations that involve + - * / with bitwise operators?

A XOR (A - 4) = 5
The binary representation of 5 is 101, so we know that A and A - 4 have the very same bit values, except the first one and the third one (from right to left). Since the fourth digit is unchanged (otherwise the number would be greater or equal than 8), so the third bit of A was 1, but the most important clue is that 5 is odd and we are XOR-ing A with A - 4. We know that the value of the last bit of a number determines whether it is pair or odd and we know that subtracting or adding a pair number to an integer will leave it odd if it was odd and will leave it pair if it was pair, So A - 4 will be odd if A was odd and will be pair if A was pair. Bitwise XOR-ing a pair number with another pair number or an odd number with another odd number will result in a pair number. So, A XOR (A - 4) = 5 has no solution for unsigned integers if we have infinite memory space allocated to them.
This is how you can solve it in your mind. Of course, a more detailed explanation could be given for each type of equation, but the solution of any equation type involving bitwise operations is a complete field which spans beyond the borders of a SO answer. If you want to program this, then you will have a difficult project to implement, but always start from the simplest, the evident.

Related

Why does b = (b - x) & x result in getting the next subset?

The Competitive Programmer's Handbook on page 99 suggests the following way of going through all subsets of a set x (the set bits represent the numbers in the set):
int b = 0;
do {
// Process subset b
} while (b = (b - x) & x);
I understand all the background about bit representation and bitwise operators.
What I am not understanding is why b = (b - x) & x results in getting the next subset.
This post gives an example, but does not provide an insight.
So, why does this work?
Things become clearer when we remember two's complement. The negative of a number is just 1 plus the bitwise NOT of that number. Thus,
(b - x) = (b + ~x + 1)
Let's work through an example of one iteration of the algorithm. Then I'll explain the logic.
Suppose
x = . 1 1 . . 1 .
b = . [.][.] . . [1] .
^
where . denotes zero.
Let's define "important" bits to be the bits that are in the same position as a 1 in x. I've surrounded the important bits with [], and I've marked the right-most important zero in b with ^.
~x = 1 [.][.] 1 1 [.] 1
~x + b = 1 [.][.] 1 1 [1] 1
~x + b + 1 = 1 [.][1] . . [.] .
(~x + b + 1) & x = . [.][1] . . [.] .
Notice that ~x + b always has a string of ones to the right of the right-most important zero of b. When we add 1, all those ones become zeros, and the right-most important zero becomes a 1.
If we look only at the important bits, we see that b transformed from [.][.][1] into [.][1][.]. Here are what the important bits will be if we continue:
[.][1][.]
[.][1][1]
[1][.][.]
[1][.][1]
[1][1][.]
[1][1][1]
If we write the important bits side-by-side like this, as if they were a binary number, then the operation effectively increments that number by 1. The operation is counting.
Once all the important bits are ones, (b - x) & x simply becomes (x - x) & x, which is 0, causing the loop to terminate.
By that point, we've encountered all 2^n possible values of the n important bits. Those values are the subsets of x.

What is this C++ code using operator ^?

What does this code mean?
int possible = 1;
for (int i = 0; i < n - 1; ++i){
possible += (n_size[i] ^ n_size[i + 1]) < 0;
}
I think this is ^ XOR, but how is it working in this code? That's strange,
Because I thought when we use XOR we have just 0 or 1.
Please, help me to understand.
Let's see this line :
possible += (n_size[i] ^ n_size[i + 1]) < 0;
We don't know about n_size but I'll suppose it is an array of n int. So we XOR (bitwise) two consecutive terms of n_size, and determine the sign of the result (by comparing it to 0).
Bitwise-XOR is operating bit per bit, so (ABCD = 1011 ^ 0101 <=> A = 1 ^ 0 , B = 0 ^ 1, C = 1 ^ 0, D = 1 ^ 1).
int are encoded in a certain manner, which allows us to get the sign with the most-significant bit (in the number 0bX???????, if X=1 the number is negative, else the number is positive).
So (A ^ B) < 0 is equivalent to (A < 0) ^ (B < 0).
So this line increments possible when two consecutive terms have not the same sign.
Finally, possible counts the number of consecutive terms alterning their sign.
PS : notice that float and double have their sign determined by their most-significant-bit too, so it works the same if n_size is an array of float or double.
As coderedoc was a little short in his comment: ^ is a bit-wise operator, just as | and &, too. Those operators are applied on every pair of corresponding bits (and for such a pair, XOR as you understood it) within two variables:
unsigned char c1 = 0b11001010;
unsigned char c2 = 0b10101100;
unsigned char c3 = c1 ^ c2; // == 0b01100110
unsigned char c4 = c1 & c2; // == 0b11101110
unsigned char c5 = c1 | c2; // == 0b10001000

Can XorShift return zero?

I've been reading about the XorShift PRNG especially the paper here
A guy here states that
The number lies in the range [1, 2**64). Note that it will NEVER be 0.
Looking at the code that makes sense:
uint64_t x;
uint64_t next(void) {
x ^= x >> 12; // a
x ^= x << 25; // b
x ^= x >> 27; // c
return x * UINT64_C(2685821657736338717);
}
If x would be zero than every next number would be zero too. But wouldn't that make it less useful? The usual use-pattern would be something like min + rand() % (max - min) or converting the 64 bits to 32 bits if you only need an int. But if 0 is never returned than that might be a serious problem. Also the bits are not 0 or 1 with the same probability as obviously 0 is missing so zeroes or slightly less likely. I even can't find any mention of that on Wikipedia so am I missing something?
So what is a good/appropriate way to generate random, equally distributed numbers from XorShift64* in a given range?
Short answer: No it cannot return zero.
According the Numeric Recipes "it produces a full period of 2^64-1 [...] the missing value is zero".
The essence is that those shift values have been chosen carefully to make very long sequences (full possible one w/o zero) and hence one can be sure that every number is produced. Zero is indeed the fixpoint of this generator, hence it produces 2 sequences: Zero and the other containing every other number.
So IMO for a sufficiently small range max-min it is enough to make a function (next() - 1) % (max - min) + min or even omitting the subtraction altogether as zero will be returned by the modulo.
If one wants better quality equal distribution one should use the 'usual' method by using next() as a base generator with a range of [1, 2^64)
I am nearly sure that there is an x, for which the xorshift operation returns 0.
Proof:
First, we have these equations:
a = x ^ (x >> 12);
b = a ^ (a << 25);
c = b ^ (b >> 27);
Substituting them:
b = (x ^ x >> 12) ^ ((x ^ x >> 12) << 25);
c = b ^ (b >> 27) = ((x ^ x >> 12) ^ ((x ^ x >> 12) << 25)) ^ (((x ^ x >> 12) ^ ((x ^ x >> 12) << 25)) >> 27);
As you can see, although c is a complex equation, it is perfectly abelian.
It means, you can express the bits of c as fully boolean expressions of the bits of x.
Thus, you can simply construct an equation system for the bits b0, b1, b2, ... so:
(Note: the coefficients are only examples, I didn't calculate them, but so would it look):
c0 = x1 ^ !x32 ^ x47 ...
c1 = x23 ^ x45 ^ !x61 ...
...
c63 = !x13 ^ ...
From that point, you have 64 equations and 64 unknowns. You can simply solve it with Gauss-elimination, you will always have a single unique solution.
Except some rare cases, i.e. if the determinant of the coefficients of the equation system is zero, but it is very unlikely in the size of such a big matrix.
Even if it happens, it would mean that you have an information loss in every iteration, i.e. you can't get all of the 2^64 possible values of x, only some of them.
Now consider the much more probable possibility, that the coefficient matrix is non-zero. In this case, for all the possible 2^64 values of x, you have all possible 2^64 values of c, and these are all different.
Thus, you can get zero.
Extension: actually you get zero for zero... sorry, the proof is more useful to show that it is not so simple as it seems for the first spot. The important part is that you can express the bits of c as a boolean function of the bits of x.
There is another problem with this random number generator. And this is that even if you somehow modify the function to not have such problem (for example, by adding 1 in every iteration):
You still can't guarantee that it won't get into a short loop *for any possible values of x. What if there is a 5 length loop for value 345234523452345? Can you prove for all possible initial values? I can't.
Actually, having a really pseudorandom iteration function, your system will likely loop after 2^32 iterations. It has a nearly trivial combinatoric reason, but "unfortunately this margin is small to contain it" ;-)
So:
If a 2^32 loop length is for your PRNG okay, then use a proven iteration function collected from somewhere on the net.
If it isn't, upgrade the bit length to at least 2^128. It will result a roughly 2^64 loop length which is not so bad.
If you still want a 64-bit output, then use 128-bit numeric internally, but return (x>>64) ^ (x&(2^64-1)) (i.e. xor-ing the upper and lower half of the internal state x).

Why does this work for determining if a number is a power of 2?

int isPower2(int x) {
int neg_one = ~0;
return !(neg_one ^ (~x+1));
}
This code works, I have implemented it and it performs perfectly. However, I cannot wrap my head around why. When I do it by hand, it doesn't make any sense to me.
Say we are starting with a 4 bit number, 4:
0100
This is obviously a power of 2. When I follow the algorithm, though, ~x+1 =
1011 + 1 = 1100
XORing this with negative one (1111) gives 0011. !(0011) = 0. Where am I going wrong here? I know this has to be a flaw in the way I am doing this by hand.
To paraphrase Inigo Montoya, "I do not think this does what you think it does".
Let's break it down.
~x + 1
This flips the bits of 'x' and then adds one. This is the same as taking the 2's complement of 'x'. Or, to put it another way, this is the same as '-x'.
neg_one ^ (~x + 1)
Using what we noted in step 1, this simplifies to ...
neg_one ^ (-x)
or more simply ...
-1 ^ (-x)
But wait! XOR'ing something with -1 is the same as flipping the bits. That is ...
~(-x)
~(-x)
This can be simplified even more if we make use of the 2's complement.
~(-x) + 0
= ~(-x) + 1 - 1
= x - 1
If you are looking for an easy way to determine if a number is a power of 2, you can use the following instead for numbers greater than zero. It will return true if it is a power of two.
(x & (x - 1)) == 0

Bitwise operation for add

Could you please help me figure out why the following expression is true:
x + y = x ^ y + (x & y) << 1
I am looking for some rules from the bitwise logic to explain this mathematical equivalent.
It's like solving an ordinary base 10 addition problem 955 + 445, by first adding all the columns individually and throwing away carried 1s:
955
445
-----
390
Then finding all the columns where there should be a carried 1:
955
445
-----
101
Shifting this and adding it to the original result:
390
+ 1010
------
1400
So basically you're doing addition but ignoring all the carried 1s, and then adding in the carried ones after, as a separate step.
In base 2, XOR (^) correctly performs addition when either of the bits is a 0. When both bits are 1, it performs addition without carry, just like we did in the first step above.
x ^ y correctly adds all the bits where x and y are not both 1:
1110111011
^ 0110111101
-------------
1000000110 (x ^ y)
x & y gives us a 1 in all the columns where both bits are a 1. These are exactly the columns where we missed a carry:
1110111011
& 0110111101
-------------
0110111001 (x & y)
Of course when you carry a 1 when doing addition you shift it left one place, just like when you add in base 10.
1000000110 (x ^ y)
+ 01101110010 + (x & y) << 1
-------------
10101111000
x + y is not equivalent to x ^ y + (x & y) << 1
However, your expression above will evaluate to true for most values since = means assignment and non-zero values mean true. == will test for equality.
EDIT
x ^ y + ((x & y) << 1) is correct with parentheses. The AND finds where a carry would happen and the shift carries it. The XOR finds where and addition would happen with no carry. Adding the two together unifies the result.