If x, y, and z are declared as boolean, then the statements operate as logical XOR and logical XNOR.
Otherwise, bitwise comparison of the variables are performed.
if (x == y) { // two input XNOR
// user code
}
if (x != y) { // two input XOR
// user code
}
if ((x == y) && (y == z)) { // three input XNOR
// user code
}
if ((x != y) || (y != z)) { // three input XOR
// user code
}
I've tested the above under various input conditions. Is this a valid way to achieve 2 and 3 input XOR and XNOR operations?
Write out the Truth Table for XOR
In1 In2 AND NAND XOR XNOR XOR
0 0 0 1 0 1 low if x==0 and y==0
0 1 0 1 1 0 high if x !=y
1 0 0 1 1 0 high if x !=y
1 1 1 0 0 1 low of x==1 and y==1
Do the same for 3 inputs:
low if x==0 and y==0 and z==0
high if x==0 and y==0 and z==1 only 1 input high
high if x==0 and y==1 and z==0 only 1 input high
low if x==0 and y==1 and z==1
high if x==1 and y==0 and z==0 only 1 input high
low if x==1 and y==0 and z==1
low if x==1 and y==1 and z==0
low if x==1 and y==1 and z==1
Am sure you can find ways to reduce this some
Or maybe make an array
if (XOR[xyz] == 1){
// true for 001, 010, 100
}
I was wondering if the code I've shown would have any problems. It seemed to work OK for the testing I've done. With x, y, z as boolean, all combinations worked OK. With x, y, z as byte, I assigned y = 100 and varied both x and z as counters in sync. When all 3 inputs were = 100, the output was true (XNOR) or false (XOR), which worked as expected. I guess my confidence level isn't the greatest yet with C, its much better with LabVIEW or VHDL.
Anyhow, the XOR and XNOR operations have many uses ... equality or inequality detection, controlled inverter, 1/2 adder, etc. I'll try a few more input variations to build my confidence.
SOLVED: Arduino 3-input XOR and 3-input XNOR operations
After more testing, the code was simplified (original post updated). Works for all possible byte values. Gives the same results as with Xilinx ISE schematic (logic) or LabVIEW block diagram (both Boolean logic or numeric type).
Test scripts are attached.
if ((x != y) || (y != z)) { // three input XOR
// user code
}
x = 0;
y = 1;
z = 1;
This will pass your test because x != y, and the y != z term won't be evaluated since in C the '||' operator means 'or' and not 'xor'. But 011 doesn't strike me as something that should trigger a 3-input hardware XOR gate...
If you really want to treat these values as booleans (since that is not a native type in C), you'll probably want to mask them:
if (( (x & 1) != (y & 1) ...
Otherwise, consider inputs of 5, 10, and 0. While 5 and 10 both evaluate to "true" in an actual boolean context, they won't be equal, and so will not evaluate in the spirit of your conditional statement.
Even this result is subject to interpretation though. Afterall, 5 & 1 evaluates to 1, while 10 & 1 evaluates to 0. Is that correct? Or do you really mean if ( ( (x || y) && !(x && y) ) || ( (y || z) && !( y && x) ) ) or something similar?
If the latter, it might be easier to just pre-condition the variables:
x = (x) ? 1 : 0;
y = (y) ? 1 : 0;
z = (z) ? 1 : 0;
Obviously if you're trying to write tight loops with as few operations as possible, which way you go depends on how many conditions are evaluated and whether you can trust the values to be constrained to 0 || 1.
This will pass your test because x != y, and the y != z term won't be evaluated since in C the '||' operator means 'or' and not 'xor'. But 011 doesn't strike me as something that should trigger a 3-input hardware XOR gate...
011 triggers the XOR because the code is testing for inequality which is simpler. For the XNOR, it tests for the equality condition which is simpler in that case.
EDIT: With the previously attached scripts, I used "random(0, 256)" for x, y, and z and even after about 5 minutes on the Arduino Due, there were still no invalid results on the print monitor.
dlloyd:
011 triggers the XOR because the code is testing for inequality which is simpler. For the XNOR, it tests for the equality condition which is simpler in that case.
EDIT: With the previously attached scripts, I used "random(0, 256)" for x, y, and z and even after about 5 minutes on the Arduino Due, there were still no invalid results on the print monitor.
Well, it's simpler, and agrees with the "odd number of inputs" principle as described on the Wiki page posted earlier, so I guess that works. Not at all what I would expect the result to be, but I guess I would have a rude awakening in that regard with real-life hardware as well.
If you're going to go there, maybe emulate the hardware cascade approach instead?
uint8_t xor (uint8_t *inputs, uint8_t input_count) {
uint8_t i; // Loop counter
uint8_t tmp; // Running value
tmp = inputs[0];
for (i = 1; i < input_count; i++) {
tmp = (tmp != inputs[i]);
if (tmp) return 1;
}
return 0;
}
uint8_t xnor (uint8_t *inputs, uint8_t input_count) {
uint8_t i; // Loop counter
uint8_t tmp; // Running value
tmp = inputs[0];
for (i = 1; i < input_count; i++) {
tmp = (tmp == inputs[i]);
if (!tmp) return 1;
}
return 0;
}
Would that do the trick? (Haven't tested it... might be overlooking an obvious snafu.) Not quite as fast as hard-coded conditionals, but scalable to the width of the counter...
If you're going to go there, maybe emulate the hardware cascade approach instead?
I'm not familiar with the hardware cascade approach, but if its only XOR and XNOR functions that can handle 2 to 8 inputs, then perhaps the 8 input statements I posted could be put into functions where the variables are assigned defaults if unused (scalable). Perhaps they would execute in fewer cpu cycles as its just one logic statement.
My idea for all this, is as I learn C would be to replicate some basic functions that are already available in other languages or software development environments. The graphic to the left is what's available in the Xilinx Schematic Editor - similar functions are available in LabVIEW.
SirNickity, and others, I truly appreciate your input - thank you.
The hardware approach is how the Wiki article said some / many hardware XOR (and XNOR) devices are built by cascading a two-input gate into the first input of another two-input gate, and so on for as many inputs as required.
I still think looking up the result in an array could be the best way to go.
Can be made to output whatever function you wanted.
byte XORarray[] = {
0, // 000
1, // 001
1, // 010
0, // 011
1, // 100
0, // 101
0, // 110,
0, // 111
};
byte XNORarray[] = {
1, // 000
0, // 001
0, // 010
1, // 011
0, // 100
1, // 101
1, // 110,
1, // 111
};
There's definitely hidden possibilities with macros. Looks easy to nest.
I like the array approach also - especially if you have multiple/unique/complex functions to implement. As the LUT is the heart of how FPGA logic works - I'll try using this for operations other than waveform data.