Utilisation des fonctions min et max en C++

à Partir de c/" class="blnk">C++, sont min et max prime sur le fmin et fmax ? Pour comparer deux entiers, fournissent-ils essentiellement la même fonctionnalité?

avez-vous tendance à utiliser un de ces ensembles de fonctions ou préférez-vous écrire les vôtres (peut-être pour améliorer l'efficacité, la portabilité, la flexibilité, etc.)?

Notes:

  1. la bibliothèque de modèles Standard C++ (STL) déclare les fonctions min et max dans l'en-tête standard C++ algorithme .

  2. la norme C (C99) fournit la fonction fmin et fmax dans la norme C math.h en-tête.

Merci d'avance!

59
demandé sur Chris Frederick 2009-10-27 19:43:01

14 réponses

fmin et fmax sont spécifiquement pour une utilisation avec des nombres à virgule flottante (d'où le "f"). Si vous l'utilisez pour ints, vous pouvez subir des pertes de performance ou de précision dues à la conversion, à la fonction Appel overhead, etc. selon votre compilateur / plate-forme.

std::min et std::max sont des templates de fonctions (définies dans l'en-tête <algorithm> ) qui fonctionnent sur n'importe quel type avec un moins-que ( < ) de l'opérateur, de sorte qu'ils peuvent fonctionner sur n'importe quel type de données qui permet une telle comparaison. Vous pouvez également fournir votre propre fonction de comparaison si vous ne voulez pas que cela fonctionne < .

c'est plus sûr puisque vous devez convertir explicitement les arguments pour correspondre quand ils ont des types différents. Le compilateur ne vous laissera pas accidentellement convertir un int 64-bit en un flotteur 64-bit, par exemple. Cette seule raison devrait faire des modèles votre choix par défaut. (Crédit à Matthieu M & bk1e)

même lorsqu'il est utilisé avec des flotteurs le modèle mai gagner en performance. Un compilateur a toujours la possibilité de lancer des appels vers des fonctions de template puisque le code source fait partie de l'Unité de compilation. Parfois il est impossible d'inline un appel à une fonction de bibliothèque, d'autre part (bibliothèques partagées, absence d'optimisation du temps de lien, etc.).

92
répondu Cogwheel 2016-07-20 13:43:32

il y a une différence importante entre std::min , std::max et fmin et fmax .

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

attendu que

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

de sorte que std::min ne remplace pas 1-1 pour fmin . Les fonctions std::min et std::max ne sont pas commutatives. Pour obtenir le même résultat avec les doubles avec fmin et fmax il faut échanger les arguments

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

mais pour autant que je puisse dire toutes ces fonctions sont implémentation défini de toute façon dans ce cas donc pour être sûr à 100% que vous devez tester comment ils sont mis en œuvre.


il y a une autre différence importante. Pour x ! = NaN :

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

attendu que

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

fmax peut être émulé avec le code suivant

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

Cela montre que std::max est un sous-ensemble de fmax .

en regardant l'Assemblée montre que Clang utilise le code de builtin pour fmax et fmin tandis que GCC les appelle d'une bibliothèque de mathématiques. L'assemblage pour clang pour fmax avec -O3 est

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

alors que pour std::max(double, double) c'est simplement

maxsd   xmm0, xmm1

Cependant, pour GCC et Clang en utilisant -Ofast fmax devient simplement

maxsd   xmm0, xmm1

donc cela montre une fois de plus que std::max est un sous-ensemble de fmax et que lorsque vous utilisez un modèle à virgule flottante plus lâche qui n'a pas nan ou zéro signé alors fmax et std::max sont les mêmes. Le même argument s'applique évidemment à fmin et std::min .

19
répondu Z boson 2016-11-22 10:58:03

vous manquez le point entier de fmin et fmax. Il a été inclus dans C99 afin que les CPU modernes puissent utiliser leurs instructions natives (SSE lu) pour la pointe flottante min et max et éviter un test et une branche (et donc une branche peut-être mal prédite). J'ai réécrit le code qui utilisait std::min et std::max pour utiliser SSE intrinsics pour min et max dans les boucles internes à la place et l'accélération était significative.

14
répondu J Ridges 2010-11-01 16:35:44

std::min et std::max sont des modèles. Ainsi, ils peuvent être utilisés sur une variété de types qui fournissent le moins que l'opérateur, y compris les flotteurs, doubles, doubles longs. Donc, si vous vouliez écrire du code C++ Générique, vous feriez quelque chose comme ceci:

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
}

quant à la performance, Je ne pense pas que fmin et fmax diffèrent de leurs homologues C++.

6
répondu sellibitze 2009-10-27 16:49:12

si votre implémentation fournit un type entier 64 bits, vous pouvez obtenir une réponse différente (incorrecte) en utilisant fmin ou fmax. Vos entiers 64 bits seront convertis en doubles, ce qui aura (au moins habituellement) une signification plus petite que 64 bits. Lorsque vous convertissez un tel nombre en un double, certains des bits les moins significatifs peuvent/seront complètement perdus.

cela signifie que deux nombres qui étaient vraiment différents pouvaient finir égaux quand convertis en double -- et le résultat sera que nombre incorrect, ce n'est pas nécessairement égal à l'une des entrées initiales.

6
répondu Jerry Coffin 2009-10-27 16:55:18

je préférerais les fonctions C++ min/max, si vous utilisez C++, parce qu'elles sont spécifiques au type. fmin/fmax force tout être converties ou de virgule flottante.

de plus, les fonctions min/max de C++ fonctionneront avec les types définis par l'utilisateur aussi longtemps que vous avez défini l'opérateur< pour ces types.

HTH

4
répondu Eric Melski 2013-04-05 20:34:18

comme vous l'avez vous-même noté, fmin et fmax ont été introduits en C99. La bibliothèque C++ Standard n'a pas les fonctions fmin et fmax . Jusqu'à ce que la bibliothèque standard C99 soit incorporée dans C++ (si jamais), les zones d'application de ces fonctions sont clairement séparées. Il n'y a pas de situation où vous avez à "préférer" l'un sur l'autre.

vous venez d'utiliser templated std::min / std::max en C++, et utilisez tout ce qui est disponible en C.

2
répondu AnT 2009-10-27 16:54:31

comme L'a souligné Richard Corden, utilisez les fonctions C++ min et max définies dans l'espace de noms std. Ils offrent une sécurité de type, et aident à éviter de comparer les types mixtes (i.e. float point vs integer) ce qui peut parfois être indésirable.

si vous trouvez que la bibliothèque C++ que vous utilisez définit min / max comme macros ainsi, elle peut causer des conflits, alors vous pouvez empêcher la macro substitution indésirable appelant les fonctions min/max de cette façon (notez les crochets supplémentaires):

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

rappelez-vous, cela va effectivement désactiver Argument dependent Lookup (ADL, également appelé Koenig lookup), dans le cas où vous voulez compter sur ADL.

2
répondu mloskot 2010-01-24 00:06:17

fmin et fmax sont seulement pour les nombres à virgule flottante et les variables doubles.

min et max sont des fonctions de modèle qui permettent la comparaison de tous les types, étant donné un prédicat binaire. Ils peuvent également être utilisés avec d'autres algorithmes de fournir des fonctionnalités complexes.

1
répondu Marcin 2009-10-27 16:49:56

utiliser std::min et std::max .

si les autres versions sont plus rapides, alors votre implémentation peut ajouter des surcharges pour celles-ci et vous bénéficierez des performances et de la portabilité:

template <typename T>
T min (T, T) {
  // ... default
}

inline float min (float f1, float f2) {
 return fmin( f1, f2);
}    
1
répondu Richard Corden 2009-10-27 19:14:14

soit dit en passant, dans cstdlib il y a __min et __max que vous pouvez utiliser.

pour plus de détails: http://msdn.microsoft.com/zh-cn/library/btkhtd8d.aspx

1
répondu Justme0 2012-10-26 11:34:40

j'utilise toujours les macros min et max pour les ints. Je ne suis pas sûr pourquoi quelqu'un utiliserait fmin ou fmax pour des valeurs entières.

le grand gotcha avec min et max est que ce ne sont pas des fonctions, même si elles leur ressemblent. Si vous faites quelque chose comme:

min (10, BigExpensiveFunctionCall())

cet appel de fonction peut être appelé deux fois en fonction de l'implémentation de la macro. En tant que tel, sa meilleure pratique dans mon organisation de ne jamais appeler min ou max avec des choses qui ne sont pas un littéral ou variable.

0
répondu popester 2009-10-27 16:46:22

fmin et fmax , de fminl et fmaxl pourrait être préféré en comparant signés et non signés entiers - vous pouvez profiter du fait que l'ensemble de la gamme de signés et non signés nombres et vous n'avez pas à vous soucier des gammes entières et des promotions.

unsigned int x = 4000000000;
int y = -1;

int z = min(x, y);
z = (int)fmin(x, y);
0
répondu Eclipse 2009-10-27 17:03:42

ne pouvait pas une implémentation C++ ciblée pour les processeurs avec des instructions SSE fournir des spécialisations de std::min et std::max pour les types float , double , et long double qui font l'équivalent de fminf , Fmin , et fminl , respectivement?

le les spécialisations fourniraient de meilleures performances pour les types à virgule flottante alors que le modèle général traiterait les types à virgule non flottante sans tenter de contraindre les types à virgule flottante en types à virgule flottante comme le feraient les fmin s et fmax es.

0
répondu user3405743 2016-02-09 22:31:41