Как вернуть true или false, не используя реляционные операторы в c? - PullRequest
0 голосов
/ 04 февраля 2019

Для развлечения предположим, что мы хотим сравнить два числа в формате double, используя язык c, и мы можем использовать только математические уравнения, которые используют арифметические операторы +, -, *, /, %, fabs() и pow(), чтобы проверить равенстводо (==), меньше (<) и больше (>).Подобно реальным реляционным операторам ==, <, and >, код, который мы пишем, должен возвращать True (1) или False (0) для каждого из типов проверок.

Например, без с использованием любых других операторов, кроме +, -, *, /, % и fabs() и pow(), если мы определим, что две переменные a и b равны, мы должны вернуть True или 1, в противном случае вернуть False или0. Лучше возвращать целые числа 0 и 1 вместо логических значений True и False.Чтобы усложнить ситуацию, мы не можем использовать реальные реляционные операторы, логические операторы, побитовые операторы или любые другие операторы.Кроме того, мы не можем использовать операторы switch или условные операторы.Как это сделать?

Я знаю, как найти меньшее значение x и y, то есть x < y можно рассчитать как ((x + y) + fabs(x-y))/2.Далее, чтобы найти x > y, это ((x + y) - fabs(x-y))/2.Однако эти уравнения возвращают значение x или y в зависимости от уравнения сравнения, и мне нужно, чтобы они возвращали 0 или 1. Аналогично, мне нужно некоторое кодовое уравнение, которое возвращает 0 или 1, если x и y равны (==)друг другу, и должны делать это, используя только +, -, *, /, %, fabs() и pow().

1 Ответ

0 голосов
/ 04 февраля 2019

Любой из заданных операторов +, -, *, /, примененный к операндам double, приведет к double, а также к функциям fabs() и pow().Таким образом, невозможно преобразовать double в integer, используя только предоставленные операторы и функции fabs() и pow().

Кроме того, оператор % предназначен только для целых чисел.Существует функция fmod(), которая обеспечивает те же функции для чисел с плавающей запятой.

Мы можем добиться того, чтобы результат наших вычислений, используя только предоставленные операторы и функции, был представлен в памяти таким же образом, какцелые числа 0 и 1.

Например, эти функции созданы для float, т. е. 32-битных чисел с плавающей запятой:

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

В этом решении используется тот факт, что меньшее из двух значений делится набольшее из двух значений приведет к значению, меньшему или равному 1.0.Затем результирующее значение после деления снова делится на две жестко закодированные константы в попытке получить число с плавающей запятой с установленным крайним правым битом, если и только если результат первого деления был точно 1.0.В конце концов, мы обращаемся к памяти, содержащей число с плавающей запятой, как если бы оно содержало целочисленный результат.


Обратите внимание, что это решение плохо протестировано и, возможно, неправильно работает во многих различных отношениях.Например, значения 2.0 и 1.9999993 ведут себя хорошо, но 2.0 и 1.9999994 считаются равными, несмотря на то, что 32-разрядное число с плавающей запятой может представлять значения 1.9999993 и 1.9999994, и они оба отличаются от 2.0.

...