Search code examples
cmathematical-expressions

How to return true or false without using the relational operators in c?


For entertainment, suppose we want to compare two numbers of format double using the c language, and we can only use mathematical equations that use the arithmetic operators +, -, *, /, %, and fabs() and pow() to check equal to (==), less than (<), and greater than (>). Similar to the real relational operators ==, <, and >, the code we write must return True (1) or False (0) for each of the different kinds of checks.

For example, without using any other operators than +, -, *, /, %, and fabs() and pow(), if we determine that two variables a and b are equal, we should return True or 1, otherwise, return False or 0. It is better to return integers 0 and 1 instead of boolean True and False. To complicate things, we cannot use the real relational operators, logical operators, bitwise operators, or any other operators. Further, we cannot use switch statements or conditional statements. How to do so?

I know how to find the smaller value of x and y, that is to say x < y can be calculated as ((x + y) + fabs(x-y))/2. Further, to find x > y, it is ((x + y) - fabs(x-y))/2. However, those equations return the value x or y depending on the comparisons equation, and I need them to return 0 or 1. Similarly, I need some code equation that returns a 0 or 1 if x and y are equal (==) to each other, and must do so using only +, -, *, /, %, and fabs() and pow().


Solution

  • Any of given operators +, -, *, / , applied to double operands will result in double, as well as fabs() and pow() function. So there is no way to convert double to integer, using only provided operators and fabs() and pow() function.

    Also, % operator is for integers only. There is a fmod() function, that provides the same functionality for floating-point numbers.

    We can achieve that the result of our calculations, using only provided operators and functions will be represented in memory in the same way, as integer 0 and 1.

    For example, these functions made for float i.e. 32bit floating point numbers:

    float largerOf(float x, float y){
        return ((x + y) + fabs(x-y)) / 2.0;
    }
    
    float smallerOf(float x, float y){
        return ((x + y) - fabs(x-y)) / 2.0;
    }
    
    int isEqual(float x, float y){
        float tmp = smallerOf(x, y) / largerOf(x, y);
        tmp /= 3.4028235E38;
        tmp /= 4194303.9999999997;
        return *((int*)(&tmp));
    }
    
    int lessThan(float x, float y){
        float tmp = smallerOf(x, y) / x;
        tmp /= 3.4028235E38;
        tmp /= 4194303.9999999997;
        return (*((int*)(&tmp)))-isEqual(x,y);
    }
    
    int greaterThan(float x, float y){
        float tmp = smallerOf(x, y) / y;
        tmp /= 3.4028235E38;
        tmp /= 4194303.9999999997;
        return (*((int*)(&tmp)))-isEqual(x,y);
    }
    

    This solution uses the fact, that smaller of two values, divided by larger of two values will result in a value less than or equal to 1.0. Then, resulting in value after division is divided again by two hardcoded constants in an attempt to get the floating-point number with the rightmost bit set if and only if result of first division was exactly 1.0. After all, we accessing the memory, containing the floating-point number, as if it was containing integer result.


    Please note, that this solution is poorly tested and may probably misbehave in many different ways. For example, values 2.0 and 1.9999993 behaves well, but 2.0 and 1.9999994 is considered equal despite the fact that 32bit floating point number can represent values 1.9999993 and 1.9999994 and they are both distinguishable from 2.0.