Are these ternary operators the same?


Hello,

What are the differences between these?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  #include <iostream>

int main()
{
    int a = 18, b = 44, total = 0, total2 = 0;

    total += (a % 2 == 0) ? b : 0; //44

    total2 += a % 2 ? b : 0; //0
    a >>= 1;
    b <<= 1;

    printf("%d\n%d", total, total2);

}
The condition (left side of the ?) is different.

(a % 2 == 0) is true when a is an even number.

a % 2 is 1 (which is treated as true) when a is an odd number.
Regarding the ternary operator itself, the only operator with lower precedence is the comma operator, so the parentheses usually aren’t necessary, but can be used for clarity.
https://en.cppreference.com/w/cpp/language/operator_precedence

My opinion is to prefer direct boolean expressions over implicit int conversions.
Last edited on
modulo and boolean logic for a bit operation is clunky ... a&1 is true for odd, a^1 is true for even gets rid of the excess == and provides a consistent look and feel. This should work on signed values, though not all bit stuff will.
Last edited on
modulo and boolean logic for a bit operation is clunky ... a&1 is true for odd

Checking if a number is even or odd isn't really a "bit operation" though. It's a mathematical property. What you do when you do a % 2 == 0 is that you're checking if the number is divisible by 2 which is what it means for a number to be even. Checking the least significant bit accomplishes the same thing but might be less obvious (and therefore make the code less "readable") to some people, especially the fact that it also works for negative numbers (assuming two's complement which is what's used in practice and what's being mandated by the standard since C++20).


a^1 is true for even

That doesn't seem to work very well.

1
2
3
4
5
6
7
8
9
#include <iostream>

int main()
{
	for (int a = 0; a <= 5; ++a)
	{
		std::cout << a << " is " << (a ^ 1 ? "even" : "odd") << "\n";
	}
}
0 is even
1 is odd
2 is even
3 is even
4 is even
5 is even
Last edited on
The correct test for even using xor is (a ^ 1) == a + 1. But this is no simpler than just using a % 2 == 0 (or just !(a % 2)). Consider:

1
2
3
4
5
6
int main() {
	for (int a = 0; a <= 5; ++a) {
		std::cout << "xor " << a << " is " << ((a ^ 1) == a + 1 ? "even" : "odd") << "\n";
		std::cout << "mod " << a << " is " << (!(a % 2) ? "even" : "odd") << "\n";
	}
}


1
2
3
4
5
6
7
8
9
10
11
12
xor 0 is even
mod 0 is even
xor 1 is odd
mod 1 is odd
xor 2 is even
mod 2 is even
xor 3 is odd
mod 3 is odd
xor 4 is even
mod 4 is even
xor 5 is odd
mod 5 is odd

you are right. And I don't see a 1 op way to test even, everything needs at least 2 operations. There should be one ... I feel like I missed something dumb, that you can't say 'is this bit 0' in one touch...
The simplest for even I can come up with is to bit inverse and then test bit 1:

 
~a & 1


or to just invert the result for odd test:

 
!(a & 1)


that you can't say 'is this bit 0' in one touch


Can this even be done in assembler? I don't recall such but I haven't used assembler for many years. As far as I remember you'd test bit 0 is set and then true (odd) or false (even) would be done with the following branch test.

I think some chips have a way to test a single bit but in general, I don't know of anything you can do in asm here that you can't do with logic ops for a typical processor.
I agree that test odd and branch to even is the most efficient way. Which is what I have done for so long that I had forgotten about the even test weirdness.
Last edited on
Registered users can post here. Sign in or register to post.