Title basically says it all. My friend gave me this as a challenge he solved in some CTF he is doing. I have thought about it for a while and can not figure it out. Also, INFINITY isn't a valid answer. Thanks.
The only way this happens in C is:
x
is an infinity (+∞ or −∞) (equivalently, HUGE_VAL
or -HUGE_VAL
in implementations that do not support infinities).x
is a NaN and the C implementation uses non-IEEE-754 behavior for NaNs.x
is adjacent to an infinity in the floating-point representation and a suitable directed rounding mode is used.x+1
and x*2
overflow and the resulting behavior not defined by the C standard happens to report the comparisons as true.x
is uninitialized and hence indeterminate and takes on different values in the two appearances of x
in x+1 == x
such that the comparison is true and, in x*2 == x
either similarly takes on different values or takes on the value zero.x
is uninitialized and has automatic storage duration and its address is not taken, and hence the behavior is not defined by the C standard, and the resulting behavior happens to report the comparisons as true.Proof:
Other than infinity, the statements are mathematically false in real numbers, and therefore this cannot arise from real-number behavior. So it must arise from some non-real-number behavior such as overflow, wrapping, rounding, indeterminate values (which may be different in each use of an object) or uninitialized values. Since *
is constrained to have arithmetic operands, we only need to consider arithmetic types. (In C++, one could define a class to make the comparisons true.)
For signed integers, non-real-number behavior with fully defined values occurs for +
and *
only when there is overflow, so that is a possibility.
For unsigned integers, non-real-number behavior with fully defined values occurs for +
and *
only when there is wrapping. Then, with wrapping modulo M, we would have x+1 = x+kM for some integer k, so 1 = kM, which is not possible for any M used in wrapping.
For the _Bool
type, exhaustive testing of the possible values eliminates them.
For floating-point numbers, non-real-number behavior with fully defined values occurs for +
and *
only with rounding, underflow, and overflow and with NaNs. NaNs never compare as equal by IEEE-754 rules, so they cannot satisfy this, except for the fact that the C standard does not require IEEE-754 conformance, so an implementation could choose to make the comparisons true.
x*2
will not underflow, since it increases the magnitude. x+1
can be made to underflow in a perverse floating-point format with smaller exponent range than precision, but this will not produce x+1 == x
. x+1 == x
can be satisfied by rounding for sufficiently large x
, but then x*2
must produce a value other than x
.
That leaves overflow. If x
is the greatest representable finite number (and hence the greatest representable number less than infinity), and the rounding mode is downward (toward −∞) or toward zero, then x+1
will yield x
and x*2
will yield x
, so the comparisons yield true. Similarly, the greatest negative representable finite number will satisfy the comparisons with rounding upward (toward +∞) or toward zero.