-4

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.

  • Huh? AFAICT, `x + 1 == x`, (grouped as `(x + 1) == x`) is _always_ false. Full stop. If there _is_ some solution, we'd need more detail (i.e. parentheses) and more elaboration on the equations. – Craig Estey Apr 03 '21 at 23:13
  • Probably `float('inf')` – Captain Trojan Apr 03 '21 at 23:27
  • @CaptainTrojan: The OP ruled that out, even though it seems a perfectly valid answer. – ShadowRanger Apr 03 '21 at 23:36
  • In some language with a Boolean type, and which also treats any positive number as equivalent to `True`, I can imagine that `x = True` would be a valid solution. I am not sure what that language would be though (it doesn't work in Python, because it doesn't treat all positive integers as equal to True). – Tony Apr 03 '21 at 23:42
  • Minus infinity then. – n. m. could be an AI Apr 03 '21 at 23:56

3 Answers3

6

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.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
6

The equalities will hold true for double x = HUGE_VAL;. Since C99, quoting cppreference.com:

The HUGE_VALF, HUGE_VAL and HUGE_VALL macros expand to positive floating point constant expressions which compare equal to the values returned by floating-point functions and operators in case of overflow

Sample code:

#include <math.h>
#include <stdio.h>

int main() {
    double x = HUGE_VAL;
    printf("%d %d\n", x + 1 == x, 2 * x == x);
    return 0;
}

Output:

1 1
dxiv
  • 16,984
  • 2
  • 27
  • 49
4

Solving for x using the C preprocessor:

#include <stdio.h>

int main() {

#define x  1,1

    if (x + 1 == x)
        printf("x + 1 == x is true\n");

    if (x * 2 == x)
        printf("x * 2 == x is true\n");

    printf("x     = %d\n", x);
    printf("x + 1 = %d\n", x + 1);
    printf("x * 2 = %d\n", x * 2);

    return 0;
}

Output (warnings omitted :):

x + 1 == x is true
x * 2 == x is true
x     = 1
x + 1 = 1
x * 2 = 1
chqrlie
  • 131,814
  • 10
  • 121
  • 189