[try Beta version]
Not logged in

 
Are these ternary operators the same?

Nov 28, 2024 at 4:27pm

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);

}
Nov 28, 2024 at 5:36pm
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.
Nov 28, 2024 at 7:45pm
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 Nov 28, 2024 at 7:48pm
Nov 29, 2024 at 12:15am
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 Nov 29, 2024 at 12:18am
Nov 29, 2024 at 11:12am
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 Nov 29, 2024 at 11:38am
Nov 29, 2024 at 4:07pm
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

Nov 30, 2024 at 11:19pm
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...
Dec 1, 2024 at 10:38am
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.

Dec 1, 2024 at 9:47pm
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 Dec 1, 2024 at 9:49pm
Topic archived. No new replies allowed.