Найти максимум три числа в C без использования условного оператора и тернарного оператора


Я должен найти максимум три числа, предоставленных Пользователем, но с некоторыми ограничениями. Он не позволяет использовать какие-либо условные операторы. Я попробовал использовать тернарный оператор, как показано ниже.

max=(a>b?a:b)>c?(a>b?a:b):c

Но опять же его ограничили использованием тернарного оператора. Сейчас я не получаю никакого понятия, как это сделать?

13 29

13 ответов:

Использование преимущества короткого замыкания в булевых выражениях:

int max(int a, int b, int c)
{
     int m = a;
     (m < b) && (m = b); //these are not conditional statements.
     (m < c) && (m = c); //these are just boolean expressions.
     return m;
}

Пояснение:

В булевой операции AND, такой как x && y, y вычисляется тогда и только тогда, когда x это правда. Если x ложно, то y не вычисляется, потому что все выражение было бы ложным, которое может быть выведено даже без вычисления y. Это называется коротким замыканием, когда значение логического выражения может быть выведено без вычисления всех операндов в оно.

Примените этот принцип к приведенному выше коду. Изначально m - это a. Теперь, если (m < b) истинно, то это означает, что b больше, чем m (что на самом деле a), поэтому второе подвыражение (m = b) вычисляется и m устанавливается в b. Если же (m < b) ложно, то второе подвыражение не будет вычислено и m останется a (что больше, чем b). Аналогичным образом вычисляется второе выражение (в следующей строке).

Короче говоря, вы можно прочитать выражение (m < x) && (m = x) следующим образом: set m to x если и только если m меньше, чем x то есть (m < x) истинно. Надеюсь, это поможет вам понять код.

Тестовый код:

int main() {
        printf("%d\n", max(1,2,3));
        printf("%d\n", max(2,3,1));
        printf("%d\n", max(3,1,2));
        return 0;
}

Вывод:

3
3
3

Онлайн-демонстрация: http://www.ideone.com/8045P

Примечание реализация max выдает предупреждения, поскольку вычисляемые выражения не используются:

Прог.c: 6: предупреждение: значение вычисленный не используется
еда.c: 7: предупреждение: вычисленное значение не используется

Чтобы избежать этих (безвредных) предупреждений, вы можете реализовать max следующим образом:

int max(int a, int b, int c)
{
     int m = a;
     (void)((m < b) && (m = b)); //these are not conditional statements.
     (void)((m < c) && (m = c)); //these are just boolean expressions.
     return m;
}
Фокус в том, что теперь мы приводим булевы выражения к void, что вызывает подавление предупреждений :

Предполагая, что вы имеете дело с целыми числами, как насчет:

#define max(x,y) (x ^ ((x ^ y) & -(x < y)))
int max3(int x, int y, int z) {
    return max(max(x,y),z);
}

Просто чтобы добавить еще одну альтернативу, чтобы избежать условного выполнения (который не является тем, который я бы использовал, но кажется отсутствующим в наборе решений):

int max( int a, int b, int c ) {
   int l1[] = { a, b };
   int l2[] = { l1[ a<b ], c };
   return l2[ l2[0] < c ];
}
Этот подход использует (как и большинство других) тот факт, что результат булева выражения при преобразовании в int дает либо 0, либо 1. Упрощенный вариант для двух значений будет следующим:
int max( int a, int b ) {
   int lookup[] { a, b };
   return lookup[ a < b ];
}

Если выражение a<b верно, мы возвращаем b, бережно хранимый в первом индексе массива поиска. Если выражение возвращает false, затем мы возвращаем a, который хранится как элемент 0 массива поиска. Используя это как строительный блок, вы можете сказать:

int max( int a, int b, int c ) {
   int lookup[ max(a,b), c ];
   return lookup[ max(a,b) < c ];
}

, который может быть тривиально преобразован в код выше, избегая второго вызова внутреннего max, используя результат, уже сохраненный в lookup[0], и вставляя исходный вызов в max(int,int).


(Эта часть - просто еще одно доказательство, которое вы должны измерить, прежде чем делать выводы, см. редактирование в конце)

Относительно чего буду ли я на самом деле использовать... Ну, вероятно, тот, который @ Foo Baa здесь модифицирован для использования встроенной функции, а не макроса. Следующим вариантом будет либо этот, либо тот, который указан в @MSN здесь.

Общим знаменателем этих трех решений, отсутствующих в общепринятом ответе, является то, что они не только избегают синтаксической конструкции if или тернарного оператора ?:, но и вообще избегают ветвления, что может иметь влияние в случае, если эти три решения не совпадают. спектакль. ветвь-предиктор в ЦП не может пропустить, когда нет ветвей.

Рассматривая производительность, сначала измерьте, а затем подумайте

Я фактически реализовал несколько различных опций для 2-way max и проанализировал сгенерированный компилятором код. Следующие три решения генерируют все тот же ассемблерный код:

int max( int a, int b ) { if ( a < b ) return b; else return a; }
int max( int a, int b ) { return (a < b? b : a ); }
int max( int a, int b ) {
   (void)((a < b) && (a = b));
   return a;
}

Что неудивительно, так как все три представляют собой одно и то же операция. Интересная часть информации заключается в том, что сгенерированный код не содержит никакой ветви. Реализация проста с помощью инструкции cmovge (тест выполняется с помощью g++ на платформе intel x64):

movl    %edi, %eax       # move a into the return value
cmpl    %edi, %esi       # compare a and b
cmovge  %esi, %eax       # if (b>a), move b into the return value
ret

Фокус заключается в условной инструкции перемещения, которая избегает любой потенциальной ветви.

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

Обновление: глядя на это 4 года спустя, я вижу, что это плохо работает, если два или более значений оказываются равными. Замена > на >= изменяет поведение, но не устраняет проблему. Он все еще может быть спасен, поэтому я не буду его удалять, но не используйте его в производственном коде.


Ладно, вот мой:

int max3(int a, int b, int c)
{
    return a * (a > b & a > c) +
           b * (b > a & b > c) +
           c * (c > a & c > b);
}
Обратите внимание, что использование & вместо && позволяет избежать любого условного кода; он опирается на тот факт, что > всегда дает 0 или 1. (Код генерируемые для a > b могут включать в себя условные переходы, но они не видны из C.)
int fast_int_max(int a, int b)
{
    int select= -(a < b);
    unsigned int b_mask= select, a_mask= ~b_mask;

    return (a&a_mask)|(b&b_mask);
}

int fast_int_max3(int a, int b, int c)
{
    return fast_int_max(a, fast_int_max(b, c));
}

Логически значимые операторы (включая b), либо все нулевые биты (если a

int max(int a, int b)
{
    long d = (long)b - (long)a;
    int m = (int)(d >> 63);
    return a & m | b & ~m;
}

int max(int a, int b, int c)
{
    long d;
    int m;
    d = (long)b - (long)a;
    m = (int)(d >> 63);
    a = a & m | b & ~m;
    d = (long)c - (long)a;
    m = (int)(d >> 63);
    return a & m | c & ~m;
}

Никаких условных обозначений. Только гипс для uint. Совершенное решение.

int abs (a) { return (int)((unsigned int)a); }
int max (a, b) { return (a + b + abs(a - b)) / 2; }
int min (a, b) { return (a + b - abs(a - b)) / 2; }


void sort (int & a, int & b, int & c)
{
   int max = max(max(a,b), c);
   int min = min(min(a,b), c);
   int middle = middle = a + b + c - max - min;
   a = max;
   b = middle;
   c = min;
}
#include "stdafx.h"
#include <iostream>
int main()
{       
        int x,y,z;
        scanf("%d %d %d", &x,&y, &z);
        int max = ((x+y) + abs(x-y)) /2;
        max = ((max+z) + abs(max-z)) /2;
        printf("%d ", max);
        return 0;
}            

Вы можете использовать этот код, чтобы найти наибольший из двух:

max{a,b} = abs(a-b)/2 + (a+b)/2

Затем используйте его снова, чтобы найти третье число:

max{a,b,c} = max(a,max(b,c))

Смотрите, что это работает для положительных чисел вы можете изменить его на работу для отрицательных, а также.

Нетусловных операторов , только циклы и назначения. И совершенно по-другому формируют чужие ответы:)

while (a > b)
{
    while (a > c)
    {
        tmp = a;
        goto finish;
    }
    tmp = c;
    goto finish;
}
while (b > c)
{
    tmp = b;
    goto finish;
}
tmp = c;
finish: max = tmp;
int compare(int a,int b, intc)
{
    return (a > b ? (a > c ? a : c) : (b > c ? b : c))
}

Попробуйте это.

#include "stdio.h"
main() {
    int a,b,c,rmvivek,arni,csc; 
    printf("enter the three numbers");
    scanf("%d%d%d",&a,&b,&c);
    printf("the biggest value is %d",(a>b&&a>c?a:b>c?b:c));
}
max =  a > b ? ( a > c ? a : c ) : ( b > c ? b : c ) ;