sintaxis programa lenguaje funciones estructuras estructura ejemplos definicion comandos codigos basicos c++ c max min

programa - Uso de funciones mínimas y máximas en C++



programa en c++ (14)

¿No podría una implementación de C ++ dirigida a procesadores con instrucciones SSE proporcionar especializaciones de std :: min y std :: max para los tipos float , double y long double que hacen el equivalente de fminf , fmin y fminl , respectivamente?

Las especializaciones proporcionarían un mejor rendimiento para los tipos de punto flotante, mientras que la plantilla general manejaría los tipos de punto no flotante sin intentar forzar los tipos de punto flotante en tipos de punto flotante de la manera en que fmin s y fmax es.

Desde C ++, ¿son preferibles min y max sobre fmax y fmax ? Para comparar dos enteros, ¿proporcionan básicamente la misma funcionalidad?

¿Tiende a usar uno de estos conjuntos de funciones o prefiere escribir el suyo propio (tal vez para mejorar la eficiencia, la portabilidad, la flexibilidad, etc.)?

Notas:

  1. La biblioteca de plantillas estándar de C ++ (STL) declara las funciones max y max en el encabezado del algorithm estándar de C ++.

  2. El estándar C (C99) proporciona la función fmax y fmax en el encabezado estándar de C math.h

¡Gracias por adelantado!


Como señaló Richard Corden, use las funciones C ++ mín. Y máx definidas en el espacio de nombres estándar. Proporcionan seguridad de tipos y ayudan a evitar la comparación de tipos mixtos (es decir, punto flotante frente a entero), lo que a veces puede ser indeseable.

Si encuentra que la biblioteca de C ++ que utiliza también define min / max como macros, puede causar conflictos, entonces puede evitar la sustitución de macros no deseada llamando a las funciones min / max de esta manera (observe corchetes adicionales):

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

Recuerde, esto efectivamente deshabilitará la en.wikipedia.org/wiki/Argument_dependent_name_lookup (ADL, también llamada búsqueda Koenig), en caso de que quiera confiar en ADL.


Como usted mismo observó, fmax y fmax se introdujeron en C99. La biblioteca estándar de C ++ no tiene funciones fmax y fmax . Hasta que la biblioteca estándar de C99 se incorpora a C ++ (si es que existe), las áreas de aplicación de estas funciones están claramente separadas. No hay una situación en la que tengas que "preferir" una sobre la otra.

Solo usa templated std::min / std::max en C ++, y use lo que esté disponible en C.


Hay una diferencia importante entre std::min , std::max y fmax y fmax .

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

mientras

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

Entonces std::min no es un sustituto de 1-1 para fmin . Las funciones std::min y std::max no son conmutativas. Para obtener el mismo resultado con dobles con fmax y fmax se deben intercambiar los argumentos.

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

Pero en la medida en que puedo decir que todas estas funciones están definidas por la implementación de todos modos, en este caso, para estar 100% seguro de que tiene que probar cómo se implementan.

Hay otra diferencia importante. Para x ! = NaN x ! = NaN :

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

mientras

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

fmax puede ser emulado con el siguiente código

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); }

Esto muestra que std::max es un subconjunto de fmax .

Ver el ensamblaje muestra que Clang usa código incorporado para fmax y fmax mientras que GCC los llama desde una biblioteca matemática. El ensamblaje para clang para fmax con fmax es

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

mientras que para std::max(double, double) es simplemente

maxsd xmm0, xmm1

Sin embargo, para GCC y Clang usando -Ofast fmax convierte simplemente en

maxsd xmm0, xmm1

Así que esto demuestra una vez más que std::max es un subconjunto de fmax y que cuando se usa un modelo de punto flotante más suelto que no tiene nan o cero con fmax entonces fmax y std::max son iguales. El mismo argumento obviamente se aplica a fmin y std::min .



Preferiría las funciones mínimas / máximas de C ++, si está utilizando C ++, porque son específicas del tipo. fmin / fmax forzará que todo se convierta a / desde un punto flotante.

Además, las funciones mínimas / máximas de C ++ funcionarán con los tipos definidos por el usuario siempre que haya definido el operador <para esos tipos.

HTH


Si su implementación proporciona un tipo de entero de 64 bits, puede obtener una respuesta diferente (incorrecta) utilizando fmin o fmax. Sus enteros de 64 bits se convertirán a dobles, lo que tendrá (al menos generalmente) un significado que es menor que 64 bits. Cuando convierte un número de este tipo a un doble, algunos de los bits menos significativos pueden perderse por completo.

Esto significa que dos números que realmente eran diferentes podrían terminar igual cuando se convierten al doble, y el resultado será ese número incorrecto, que no es necesariamente igual a ninguna de las entradas originales.


Siempre utilizo las macros min y max para ints. No estoy seguro de por qué alguien usaría fmin o fmax para valores enteros.

El big gotcha con min y max es que no son funciones, incluso si se parecen a ellas. Si haces algo como:

min (10, BigExpensiveFunctionCall())

Esa llamada de función puede ser llamada dos veces dependiendo de la implementación de la macro. Como tal, su mejor práctica en mi organización es nunca llamar mínimo o máximo con cosas que no sean literales o variables.


Te estás perdiendo todo el punto de fmin y fmax. Se incluyó en C99 para que las CPU modernas puedan usar sus instrucciones nativas (lea SSE) para los puntos flotantes mínimo y máximo y evitar una prueba y una derivación (y, por lo tanto, una derivación posiblemente errónea). Reescribí el código que usaba std :: min y std :: max para usar los intrínsecos SSE para min y max en bucles internos, y el aumento de velocidad fue significativo.


Use std::min y std::max .

Si las otras versiones son más rápidas, su implementación puede agregar sobrecargas para estas y obtendrá el beneficio de rendimiento y portabilidad:

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


fmin y fmax son solo para variables de punto flotante y doble.

min y max son funciones de plantilla que permiten la comparación de cualquier tipo, dado un predicado binario. También pueden usarse con otros algoritmos para proporcionar una funcionalidad compleja.


std :: min y std :: max son plantillas. Por lo tanto, se pueden usar en una variedad de tipos que brindan menos del operador, incluidos flotadores, dobles, dobles largos. Entonces, si quisieras escribir código genérico de C ++, harías algo como esto:

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 }

En cuanto al rendimiento, no creo que fmax y fmax difieran de sus contrapartes de C ++.


fmax y fmax , de fminl y fmaxl pueden ser preferibles cuando se comparan enteros con signo y sin signo; puede aprovechar el hecho de que el rango completo de números con y sin signo no tiene que preocuparse por los rangos de enteros y las promociones.

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


fmax y fmax son específicamente para uso con números de punto flotante (de ahí la "f"). Si lo usa para ints, puede sufrir pérdidas de rendimiento o precisión debido a la conversión, la sobrecarga de llamadas a funciones, etc., dependiendo de su compilador / plataforma.

std::min y std::max son funciones de plantilla (definidas en el encabezado <algorithm> ) que funcionan en cualquier tipo con un operador menor que ( < ), por lo que pueden operar en cualquier tipo de datos que permita dicha comparación. También puede proporcionar su propia función de comparación si no desea que funcione < .

Esto es más seguro ya que tiene que convertir explícitamente los argumentos para que coincidan cuando tienen diferentes tipos. El compilador no le permitirá convertir accidentalmente un int de 64 bits en un flotador de 64 bits, por ejemplo. Solo por esta razón, las plantillas deben ser su elección predeterminada. (Crédito a Matthieu M & bk1e)

Incluso cuando se usa con flotadores, la plantilla puede ganar en rendimiento. Un compilador siempre tiene la opción de incluir llamadas a funciones de plantilla, ya que el código fuente es parte de la unidad de compilación. A veces es imposible en línea una llamada a una función de biblioteca, por otro lado (bibliotecas compartidas, ausencia de optimización de tiempo de enlace, etc.).