The Three Ways of XOR
horia141.com
horia141.com
I guess the author never taught of <boolean> != <boolean>. The only thing to be careful with is that it doesn't implicitly convert arguments to boolean, so expressions like "<boolean> != (flags & Flag)" will go wrong without an explicit conversion "bool(flags & Flag)" or equivalent expression like "((flags & Flag) != 0)".
And let's not forget about the friend, ==. I've more than once seen code like "(a && b) || (!a && !b)".
A similar interesting pattern many don't think of is "bool(a1) + ... + bool(aN) == M" (particularly with M==1) and instead we see unreadable monstrosities :)
while (x --> 0) x goes to zero;
while (0 <---- x) goes much faster on some compilers (ymmv);I think maybe part of the reason is that usually you're also doing something with the value of the lhs or rhs, so you end up having to separate the cases anyway:
if (a && !b) { frob(a); }
else if (b && !a) { twiddle(b); }
else { panic(); } !a != !b
is sufficient.Well, you could also use bitwise XOR in that case.
The latter is the same as "a1 + ... + an == 1 || a1 + ... + an == 2 || ... || a1 + ... + an == n".
By the way, in Python, bool is a subtype of int (i.e., instanceof(True,int) == True), and True + True == 2. C is the same, and in Javascript booleans are converted to integers for arithmetic operations.
One might imagine it (without experience, or not thinking, of any particular programming language) as being a logical OR on Booleans - which in EE at least is frequently written '+'.
It is XNOR, not XOR (no pun intended)
Boolean algebra laws excellently help if there are many input aN. I used to use it to simplify legacy ruby codes written by c-style programmer (you can imagine how the conditions look like)
I didn't believe him until he showed me. Apparently they used to use it all the time to swap out entire segments of RAM in the S/360 without having to page out to disk or clobber other free RAM segments. It is simply:
a = a xor b
b = b xor a
a = a xor b
Three steps, same as using a placeholder 'c' variable. I think he mentioned on most of the processors of the time, 3 XOR instructions actually worked faster than 3 MOV instructions.Illustration for the non-believers:
a = 10010110
b = 01100011
a = a xor b
a = 11110101
b = 01100011 (unchanged)
b = b xor a
a = 11110101 (unchanged)
b = 10010110
a = a xor b
a = 01100011
b = 10010110
Voila!However, the semantics differ from just using a temporary variable in that if a and b are in the same memory location then the result will be zero.
This was used in an entry for the underhanded C contest [1] if I remember correctly where for an implementation of RC4 the author defined the following macro.
#define SWAP(x, y) do { x^=y; y^=x; x^=y; }
And used it for swapping the values in the substitution table for the cipher, e.g. SWAP(S[i], S[j]). The weakness was that since sometimes the indices are the same in RC4 the substitution table would be gradually replaced with zeroes. a1 = a0 ^ b0
b1 = b0 ^ a1 = b0 ^ (a0 ^ b0) = (a0 ^ b0) ^ b0 = a0
a2 = a1 ^ b1 = (a0 ^ b0) ^ a0 = (b0 ^ a0) ^ a0 = b0
The xor-linked list (https://en.wikipedia.org/wiki/XOR_linked_list) is another neat idea along the same theme.I was implementing a toy rc4 cipher. One of the steps in the ciphers involves swapping entries in an arrays of 256 elements. I thought "hey, I'm a 1337 coder, I'm going to use the xor trick".
Except it doesn't work if you're trying to swap something with itself. If you do "a[i] ^= a[j]" and i == j then you're just clearing the entry.
Taught me the valuable lesson that I shouldn't try to be a smartass while writing code and the importance of unit tests.
a = a + b
b = b + a
a = b - a
b = b - 2*ab = a - b
a = a - b
I think this works too, assuming a+b doesn't overflow.
> I think this works too, assuming a+b doesn't overflow.
Well, in two's complement arithmetic (as is used on most architectures), the intermediate overflow can be ignored, and it will work just fine.
Except that 2a, that might be trouble.
14 - 15 gives 15
1110 + 1111 = 1101
1101 - 1110 = 1111
1101 - 1111 = 1110
Overflow doesn't matter if you just want to swap. mov eax, edi
mov edi, esi
mov esi, eax
I would intuitively use the `xchg` instruction that x86-32/x86-64 provides instead. Is there a specific reason why the compiler(s) decide to generate the mentioned code instead?"Instructions with a LOCK prefix have a long latency that depends on cache organization and possibly RAM speed. If there are multiple processors or cores or direct memory access (DMA) devices then all locked instructions will lock a cache line for exclusive access, which may involve RAM access. A LOCK prefix typically costs more than a hundred clock cycles, even on single-processor systems. This also applies to the XCHG instruction with a memory operand."
So I still stand by my point: What is the reason why the compiler uses `mov` for exchanging two registers here instead of `xchg`?
"Vector path instructions are less efficient than single or double instructions because they require exclusive access to the decoders and pipelines and do not always reorder optimally. For example:
; Example 17.1. AMD instruction breakdown
xchg eax, ebx ; Vector path, 3 ops
nop ; Direct path, 1 op
xchg ecx, edx ; Vector path, 3 ops
nop ; Direct path, 1 op
This sequence takes 4 clock cycles to decode because the vector path instructions must decode alone.""Some extra treats: XOR can be considered an imparity function. When the number of inputs is even, it outputs zero, while when it is odd, it outputs one. It is also the sum part of an adder, that is, without the carry part. "
Say we have an N=4 dimensional vector space, and we use binary place values to represent units vector in a basis, like this:
w = 1000
x = 0100
y = 0010
z = 0001
Then a multivector basis could be represented e.g.:
xyz = 0111
xy = 0110
wz = 1001
Now, if ^ is the outer product:
xy^yz = xz ↔ 0110 xor 0011 = 0101.
wx^yz = wxyz ↔ 1100 xor 0011 = 1111.
and so on.
If anyone has more information about this, I'd be really interested in seeing it!
struct Example {
int elem1;
int elem2;
...
};
Example ex1 = { 1, 2, ... };
int a = ex1.elem1;
int b = ex1.elem2;
...
If we think of ex1 as a vector, and elem1 as a constant vector [1, 0, 0...] (and elem2 as a constant vector [0, 1, 0, ...] and so on) then ex1.elem1 is literally the inner product of ex1 and the constant elem1.I have no idea if that was the original thinking behind dot notation but it's neat and I like it.
https://sourceforge.net/projects/g25/?source=directory
The XOR trick is close to slide 16 of http://www.science.uva.nl/research/ias/ga/gaigen/files/20020...
...
How to compute the geometric product of unit orthogonal basis blades (3/3) If we represent each basis vector with a specific bit in a binary number (e1 = 001b, e2 = 010b, e3 = 100b), computing the geometric product of basis blades is exactly the xor operation on binary numbers!
(e1^e2)(e2^e3) = e1^e3
011b xor 110b = 101b
We have to take care of the signs though:- basis vectors have to be rearranged into a specific order before they can annihilate each other (this rearranging causes a sign change in the result). This can also be computed binary. - signature of annihilated basis vectors can change the sign as well.
Well, in C there's just no need. The main raison d'etre for && and || over & and | is that you can exploit their short circuiting behaviour. A hypothetical ^^ operator wouldn't bring anything extra to the table.
Wonder when the current AI summer will come to an end...
My guess is it's still early days on the AI boom.
My comment on AI Winter:
Minor correction: Marvin and Seymour's Perceptrons book was published around 1969 and nuked neural nets around there. AI winter set in in the 80s as expert systems and similar crude symbolic systems proved not to be scalable (I was at that AAAI in 1984 and remember that panel well).
Moore's law rescued NNs and is about to rescue symbolic AI as well.
Are we really closer to AI in a significant way today? Chomsky makes an interesting argument to the contrary. He points out that any physical system, say the motion of falling bodies, can be closely modeled statistically given enough data points. However, this modeling gives us very little insight into why the system behaves in that manner, i.e. gravity.
Of course, this presumes that the human brain isn't just an advanced statistical model trained by billions of years of evolution.
While 2-input XOR behaves as “one or the other but not both”, a many-input gate is generally implemented by chaining other XORs and the chaining causes even/odd parity instead of a “must be only one” behavior [1].
[1] and sorry if I'm falling victim to the difficulty of interpreting tone on the internet
(F == F) == T in fact is T