Вопрос

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

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

Примечания:

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

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

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

Это было полезно?

Решение

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

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

Это безопаснее, так как вам нужно явно преобразовать аргументы для соответствия, когда они имеют разные типы. Например, компилятор не позволит вам случайно преобразовать 64-битное int в 64-битное число с плавающей точкой. Одна только эта причина должна сделать шаблоны вашим выбором по умолчанию. (Благодарю Матье М & Amp; 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 не является заменой 1 : 1 для 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:

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 или тогда со знаком ноль fmax и std::max являются одними и теми же.Тот же аргумент, очевидно, применим и к fmin и std::min.

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

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

template<typename T>
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 - и в результате получится неправильное число, которое не обязательно будет равно ни одному из исходных входных данных.

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

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

HTH

Как вы сами отметили, fmin и fmax были представлены в C99. Стандартная библиотека C ++ не имеет функций std::min и std::max. Пока стандартная библиотека C99 не будет включена в C ++ (если вообще когда-либо), области применения этих функций четко разделены. Там нет ситуации, когда вам, возможно, придется & Quot; предпочесть & Quot; один над другим.

Вы просто используете шаблонный <=> / <=> в C ++ и используете все, что доступно в C.

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

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

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

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

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

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

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

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

template <typename T>
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

Не могла бы реализация C ++, предназначенная для процессоров с инструкциями SSE, обеспечить специализацию std:: мин и std:: макс для типов плавать, двойной, и длинный двойной которые выполняют эквивалент fminf, fmin, и fminl, соответственно?

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

Я всегда использую макросы min и max для целых. Я не уверен, почему кто-то использовал бы 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);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top