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



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



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



Примечания:




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


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



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

2028   14  

14 ответов:

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

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

это безопаснее, так как вы должны явно преобразовать аргументы, чтобы соответствовать, когда они имеют разные типы. Компилятор не позволит вам случайно преобразовать 64-разрядный int в 64-разрядный float, например. Только по этой причине шаблоны должны быть выбраны по умолчанию. (Кредит Матье 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 не является 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 for 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 используется -Ofastfmax становится просто

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

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

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

HTH

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

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

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

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

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

помните, что это будет эффективно отключить Аргумент Зависимого Поиска (ADL, также называемый Koenig lookup), в случае, если вы хотите полагаться на 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

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

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

min (10, BigExpensiveFunctionCall())

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

fmin и fmax, of 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 и двойной которые делают эквивалент fminf,fmin и fminl, соответственно?

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

Comments

    Ничего не найдено.