Использование функций min и max В C++
из C++, are min и max предпочтительнее fmin и fmax? Для сравнения двух целых чисел, они обеспечивают в основном ту же функциональность?
вы склонны использовать один из этих наборов функций или предпочитаете писать свои собственные (возможно, для повышения эффективности, переносимости, гибкости и т. д.)?
Примечания:
библиотека стандартных шаблонов C++ (STL) объявляет
minиmaxфункции в стандартном C++ алгоритм заголовок.стандарт C (C99) обеспечивает
fminиfmaxфункция в стандартном C математика.h заголовок.
спасибо заранее!
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 forfmaxС-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, offminlи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