1. ## Ternary operator

Hello,

I have a silly question:

Why do programmers use the ternary operator as shown in the abs2 function with the extra pair of brackets enclosing the conditional statement? To improve readability? As far as I know the < operator has higher precedence so the code in abs1 below is perfectly valid.

Code:
```int abs1(int a)
{
return (a < 0 ? -a : a);
}

int abs2(int a)
{
return ((a < 0) ? -a : a);
}```

2. Originally Posted by kkk
Why do programmers use the ternary operator as shown in the abs2 function with the extra pair of brackets enclosing the conditional statement? To improve readability? As far as I know the < operator has higher precedence so the code in abs1 below is perfectly valid.
Perhaps they simply do not remember with absolute certainly what the relevant precedence rules are. Case in point: why did you use the return statement with the extra pair of parentheses for abs1? After all, the code in abs3 below is perfectly valid:
Code:
```int abs3(int a)
{
return a < 0 ? -a : a;
}```

3. This may also be a good time to point out that this function returns the wrong result for the most negative integer in a two's complement system.
It would probably be best to make the return type unsigned.

4. Originally Posted by iMalc
This may also be a good time to point out that this function returns the wrong result for the most negative integer in a two's complement system.
It would probably be best to make the return type unsigned.
What on earth for?
Code:
```#include<stdio.h>
int main( void )
{
signed int x = -5;
printf( "%u\n", (unsigned int) x );
return 0;
}```
Oops!

Also, if subtracting a negative doesn't give you a positive, then your compiler fails at math.

Quzah.

5. O_o

As a matter of interest, C and C++ have some slight differences in precedence and treat the conditional operator differently. For this example, it is clearly not the case, but code written for compatibility with C and C++ will often have an extra set of parentheses in one or more of the expressions.

Soma

6. Originally Posted by quzah
What on earth for?
As I said, it's for this:
Code:
`abs(-2147483648);`

7. Originally Posted by iMalc
As I said, it's for this:
I guess I'm missing something in your explanation, because changing the type of -5 to unsigned doesn't make it 5.

Quzah.

8. Originally Posted by iMalc
As I said, it's for this:
Unfortunately, changing the return type to unsigned int will not fix the problem since the correct return value for abs(-2147483648) is 2147483648, but with two's complement INT_MAX in your example is presumably 2147483647.

9. O_o

Why don't you two try to take in all he said instead of just any one part.

In most "Two's Complement" machinery, -2147483648 has the same binary representation as 2147483648 when the binary is treated as a positive integer value. Furthermore negating -2147483648, if it is the largest negative value, result in the same -2147483648 value. This is a well known issue.

I guess I'm missing something in your explanation, because changing the type of -5 to unsigned doesn't make it 5.
He didn't say to drop the act of negation. That makes your casting of "-5" example ridiculous. He said to change the return type so that it is large enough to represent the absolute value of the largest associated negative value as handled in most "Two's Complement" machinery.

Unfortunately, changing the return type to unsigned int will not fix the problem since the correct return value for abs(-2147483648) is 2147483648, but with two's complement INT_MAX in your example is presumably 2147483647.
Your logic is also flawed. The `INT_MAX' value probably is 2147483647, but you'd be needing to think about `UINT_MAX' where the value is 4294967295.

Soma

10. Originally Posted by phantomotap
you'd be needing to think about `UINT_MAX' where the value is 4294967295.
Oh yeah, in that case iMalc's suggestion works.

11. Originally Posted by laserlight
Oh yeah, in that case iMalc's suggestion works.
So then what happens when you cast it back to signed when your function returns the value? Because we weren't talking about unsigned values here.
Code:
```signed char c = -128;
c = abs( c );```
If we were, we wouldn't need an abs function. Wikipedia:
0 1 1 1 1 1 1 1 = 127
0 1 1 1 1 1 1 0 = 126
0 0 0 0 0 0 1 0 = 2
0 0 0 0 0 0 0 1 = 1
0 0 0 0 0 0 0 0 = 0
1 1 1 1 1 1 1 1 = −1
1 1 1 1 1 1 1 0 = −2
1 0 0 0 0 0 0 1 = −127
1 0 0 0 0 0 0 0 = −128
Ok, so you make that signed -128 to 128, and then it's assigned right back to a signed char. Wouldn't that just turn it right back into signed -128?

I can't seem to wrap my head around this one.

Quzah.

12. Originally Posted by quzah
So then what happens when you cast it back to signed when your function returns the value? Because we weren't talking about unsigned values here.
I think that is fine though for this edge case: for a signed destination type, if the return type is signed, it is problematic; otherwise, it is still problematic. But if the destination type is unsigned, and if the return type is unsigned, it is not problematic, so at least there's a win there.

13. Practically, assuming a binary representation, signed integral types (signed char, short, int, long) have a property that they are asymmetric (i.e. XXX_MIN is not equal to -XXX_MAX for XXX corresponding to each of the signed integral types). The standard neither encourages nor discourages this, because it only specifies bounds on what those XXX_MIN and XXX_MAX values may have and, for each type, those values have the same magnitude. For example, it specifies (a little indirectly) that both INT_MIN and INT_MAX must both have a magnitude at least 32767. It does not require that INT_MIN be equal to -INT_MAX.

If INT_MIN is not equal (mathematically) to -INT_MAX, then there is one value (one of those two extrema) for which multiplying by -1 gives undefined behaviour if the result is required to be stored in a value of the same type. So, if x is of type int with value -32768, INT_MIN has the value -32768, INT_MAX has the value 32767 then computing -x gives undefined behaviour if the result is to be stored in a variable of type int. In practice, depending on the underlying representation, that "undefined behaviour" might wrap around (for example, -INT_MIN may give the value INT_MIN), but there is nothing in the standard preventing some other type of behaviour (such as reporting an integer overflow).

The result is, however, always defined if the result of computing -x is to be stored in an unsigned variable. All operations on unsigned integral types are described mathematically in terms of modulo arithmetic (for example, adding 1 to UINT_MAX will yield zero, converting -1 to unsigned will yield UINT_MAX). One cute side effect is that
Code:
```unsigned abs4(int a)
{
return a < 0 ? -a : a;
}```
will always yield correct results (unless its return value is converted back to int) but
Code:
```int abs3(int a)
{
return a < 0 ? -a : a;
}```
may exhibit undefined behaviour for some (edge case) values.