Использование функций min и max в C ++

Из C ++, min и max предпочтительнее fmin и fmax ? Для сравнения двух целых чисел они обеспечивают в основном одну и ту же функциональность?

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

Заметки:

  1. Стандартная библиотека шаблонов C ++ (STL) объявляет min и max функции в стандартном заголовке алгоритма C ++.

  2. Стандарт C (C99) предоставляет fmin и fmax в стандартном заголовке C math.h.

Заранее спасибо!

    fmin и fmax специально предназначены для использования с числами с плавающей запятой (отсюда и «f»). Если вы используете его для ints, вы можете потерять производительность или прецизионные потери из-за конверсии, накладных расходов функций и т. Д. В зависимости от вашего компилятора / платформы.

    std::min и std::max – это функции шаблона (определенные в заголовке ), которые работают с любым типом с меньшим ( < ) оператором, поэтому они могут работать с любым типом данных, который позволяет такое сравнение. Вы также можете предоставить свою собственную функцию сравнения, если вы не хотите, чтобы она работала. < .

    Это безопаснее, так как вы должны явно преобразовывать аргументы, чтобы соответствовать, когда у них разные типы. Компилятор не позволит вам случайно преобразовать 64-битный int в 64-битный float, например. Только эта причина должна сделать шаблоны вашим выбором по умолчанию. (Кредит Matthieu M & bk1e)

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

    Существует важная разница между std::min , std::max и fmin и fmax .

     std::min(-0.0,0.0) = -0.0 std::max(-0.0,0.0) = -0.0 

    в то время как

     fmin(-0.0, 0.0) = -0.0 fmax(-0.0, 0.0) = 0.0 

    Поэтому std::min не является заменой fmin на fmin . Функции std::min и std::max не являются коммутативными. Чтобы получить тот же результат с удвоениями с fmin и fmax нужно поменять аргументы

     fmin(-0.0, 0.0) = std::min(-0.0, 0.0) fmax(-0.0, 0.0) = std::max( 0.0, -0.0) 

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


    Есть еще одно важное различие. Для x ! = NaN x ! = NaN :

     std::max(Nan,x) = NaN std::max(x,NaN) = x std::min(Nan,x) = NaN std::min(x,NaN) = x 

    в то время как

     fmax(Nan,x) = x fmax(x,NaN) = x fmin(Nan,x) = x fmin(x,NaN) = x 

    fmax можно эмулировать следующим кодом

     double myfmax(double x, double y) { // z > nan for z != nan is required by C the standard int xnan = isnan(x), ynan = isnan(y); if(xnan || ynan) { if(xnan && !ynan) return y; if(!xnan && ynan) return x; return x; } // +0 > -0 is preferred by C the standard if(x==0 && y==0) { int xs = signbit(x), ys = signbit(y); if(xs && !ys) return y; if(!xs && ys) return x; return x; } return std::max(x,y); } 

    Это показывает, что std::max является подмножеством fmax .

    Глядя на сборку, показано, что Clang использует встроенный код для fmax и fmin тогда как GCC вызывает их из математической библиотеки. Сборка для clang для fmax с -O3 является

     movapd xmm2, xmm0 cmpunordsd xmm2, xmm2 movapd xmm3, xmm2 andpd xmm3, xmm1 maxsd xmm1, xmm0 andnpd xmm2, xmm1 orpd xmm2, xmm3 movapd xmm0, xmm2 

    тогда как для std::max(double, double) это просто

     maxsd xmm0, xmm1 

    Однако для GCC и Clang с использованием -Ofast fmax становится просто

     maxsd xmm0, xmm1 

    Таким образом, это еще раз показывает, что std::max является подмножеством fmax и что, когда вы используете более свободную модель с плавающей запятой, которая не имеет nan или signed zero, тогда fmax и std::max являются одинаковыми. Тот же аргумент, очевидно, применим к fmin и std::min .

    Вам не хватает всей точки fmin и fmax. Он был включен в C99 так, чтобы современные процессоры могли использовать свои собственные инструкции (чтение SSE) для минимальных и максимальных значений с плавающей запятой и избегать тестирования и ветвления (и, следовательно, возможно, неправильно сoutlookированной ветви). Я переписал код, который использовал std :: min и std :: max, чтобы использовать встроенные функции SSE для min и max во внутренних циклах, и ускорение было значительным.

    std :: min и std :: max – это шаблоны. Таким образом, они могут использоваться на различных типах, которые обеспечивают меньше оператора, включая поплавки, удваивает, удваивают. Итак, если вы хотите написать общий код на C ++, вы бы сделали что-то вроде этого:

     template T const& max3(T const& a, T const& b, T const& c) { using std::max; return max(max(a,b),c); // non-qualified max allows ADL } 

    Что касается производительности, я не думаю, что fmin и fmax отличаются от своих C ++-аналогов.

    Если ваша реализация обеспечивает 64-разрядный целочисленный тип, вы можете получить другой (неверный) ответ, используя fmin или fmax. Ваши 64-битные целые числа будут преобразованы в двойные, что (как минимум, обычно) имеет значение, меньшее, чем 64-битные. Когда вы конвертируете такое число в double, некоторые из наименее значимых бит могут / будут полностью потеряны.

    Это означает, что два числа, которые были действительно разными, могут быть равны при преобразовании в double – и результатом будет то неправильное число, которое не обязательно равно ни одному из исходных входов.

    Я бы предпочел функции C ++ min / max, если вы используете C ++, потому что они зависят от типа. fmin / fmax заставит все преобразовать в / из плавающей запятой.

    Кроме того, функции C ++ min / max будут работать с определенными пользователем типами, пока вы определили оператор <для этих типов.

    НТН

    Как вы отметили, fmin и fmax были введены на C99. Стандартная библиотека C ++ не имеет fmin и fmax . До тех пор, пока стандартная библиотека C99 не будет включена в C ++ (если вообще когда-либо), области приложений этих функций будут четко разделены. Там нет ситуации, когда вам, возможно, придется «отдать предпочтение» друг другу.

    Вы просто используете шаблонный std::min / std::max в C ++ и используете все, что доступно в C.

    Как указал Ричард Корден, используйте функции C ++ min и max, определенные в пространстве имен std. Они обеспечивают безопасность типов и помогают избежать сравнения смешанных типов (то есть точки с плавающей точкой и целого числа), что иногда может быть нежелательным.

    Если вы обнаружите, что используемая вами библиотека C ++ определяет min / max как macros, это может вызвать конфликты, тогда вы можете предотвратить нежелательную макроподстановку, вызывающую функции min / max таким образом (обратите внимание на дополнительные скобки):

     (std::min)(x, y) (std::max)(x, y) 

    Помните, что это эффективно отключит зависящий от аргумента поиск (ADL, также называемый поиском Koenig), если вы хотите полагаться на ADL.

    fmin и fmax предназначены только для переменных с плавающей запятой и двойной переменной.

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

    Используйте std::min и std::max .

    Если другие версии быстрее, то ваша реализация может добавить к ним перегрузки, и вы получите преимущество производительности и переносимости:

     template  T min (T, T) { // ... default } inline float min (float f1, float f2) { return fmin( f1, f2); } 

    Кстати, в cstdlib есть __min и __max вы можете использовать.

    Дополнительные сведения: http://msdn.microsoft.com/zh-cn/library/btkhtd8d.aspx

    Я всегда использую macros min и max для ints. Я не уверен, почему кто-то будет использовать fmin или fmax для целых значений.

    Большая добыча с min и max заключается в том, что они не являются функциями, даже если они выглядят как они. Если вы сделаете что-то вроде:

     min (10, BigExpensiveFunctionCall()) 

    Этот вызов функции может вызываться дважды в зависимости от реализации макроса. Таким образом, его лучшая практика в моей организации никогда не вызывать min или max с вещами, которые не являются буквальными или переменными.

    fmin и fmax , fminl и fmaxl могут быть предпочтительными при сравнении целых чисел без знака – вы можете воспользоваться тем, что весь диапазон подписанных и неподписанных чисел и вам не нужно беспокоиться о целых диапазонах и рекламных акциях.

     unsigned int x = 4000000000; int y = -1; int z = min(x, y); z = (int)fmin(x, y); 

    Не может ли реализация C ++, предназначенная для процессоров с инструкциями SSE, предоставлять специализации std :: min и std :: max для типов float , double и long double, которые соответствуют эквивалентам fminf , fmin и fminl соответственно?

    Специализации обеспечивали бы лучшую производительность для типов с плавающей точкой, в то время как общий шаблон обрабатывал бы типы с плавающей точкой, не пытаясь принуждать типы с плавающей точкой к типам с плавающей точкой таким образом, чтобы fmin и fmax es были бы.

    Interesting Posts

    Получение последней записи в каждой группе из базы данных – SQL Server 2005/2008

    Могут ли мои enums иметь дружеские имена?

    Мне нужна ячейка для автоматического заполнения, когда данные вводятся в соседнюю ячейку

    Как изменить цвет / внешний вид элемента управления EditText / anchor?

    Как изменить измененную дату файла в Windows Vista?

    Повторите элемент HTML несколько раз, используя ngFor на основе числа

    Простая страница Bootstrap не реагирует на iPhone

    Создайте архив из каталога без добавления имени каталога в архив

    Как переместить существующую установку Window 7 64bit в UEFI (из наследия)

    Как отобразить текущее значение предпочтения Android в сводке предпочтений?

    На iPhone: узнать, какая песня сейчас играет? (в музыкальном проигрывателе iPod)

    Реализация шаблона пула объектов C #

    Подсветка клавиатуры в диспетчере устройств?

    Как добавить быстрый скроллер в RecyclerView

    Как уловить ошибку сегментации в Linux?

    Давайте будем гением компьютера.