Question

À partir de C ++, min et max sont-ils préférables à fmin et fmax? Pour comparer deux nombres entiers, fournissent-ils essentiellement les mêmes fonctionnalités?

Avez-vous tendance à utiliser l'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.)?

Remarques:

  1. La bibliothèque de modèles standard C ++ (STL) déclare les fonctions <=> et <=> du langage C ++ standard algorithme .

  2. Le standard C (C99) fournit les fonctions <=> et <=> dans le standard C en-tête math.h .

Merci d'avance!

Était-ce utile?

La solution

fmin et fmax sont spécifiquement conçus pour être utilisés avec des nombres à virgule flottante (d'où le " f "). Si vous l’utilisez pour ints, vous risquez de subir des pertes de performances ou de précision dues à la conversion, aux frais généraux des appels de fonctions, etc., en fonction de votre compilateur / plate-forme.

std::min et std::max sont des fonctions de modèle (définies dans l'en-tête <algorithm> ) qui travaillent sur tout type avec un opérateur inférieur à (<), afin de pouvoir utiliser tout type de données permettant une telle comparaison. Vous pouvez également fournir votre propre fonction de comparaison si vous ne souhaitez pas que cela fonctionne <=>.

Ceci est plus sûr car vous devez convertir explicitement les arguments afin qu'ils correspondent lorsque leurs types sont différents. Le compilateur ne vous laissera pas convertir accidentellement un int de 64 bits en un float de 64 bits, par exemple. Cette seule raison devrait faire des modèles votre choix par défaut. (Merci à Matthieu M & Amp; bk1e)

Même utilisé avec des éléments flottants, le modèle peut gagner en performance. Un compilateur a toujours la possibilité d'inclure des appels à des fonctions de modèle car le code source fait partie de l'unité de compilation. Parfois, il est impossible d’inscrire un appel à une fonction de bibliothèque (bibliothèques partagées, absence d’optimisation du temps de liaison, etc.).

Autres conseils

Il existe 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

alors que

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

Donc x ! = NaN n'est pas un substitut 1-1 de -O3. Les fonctions std::max(double, double) et -Ofast ne sont pas commutatives. Pour obtenir le même résultat avec des doublons avec nan et <=>, 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 autant que je sache, tous ces les fonctions sont implémentées de toute façon dans ce cas , donc pour être sûr à 100%, vous devez tester leur implémentation.

Il existe une autre différence importante. Pour <=>:

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

alors que

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

<=> 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 <=> est un sous-ensemble de <=>.

L'examen de l'assemblage montre que Clang utilise le code intégré pour <=> et <=> alors que GCC les appelle à partir d'une bibliothèque mathématique. L'assemblage de clang pour <=> avec <=> 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 <=> c'est tout simplement

maxsd   xmm0, xmm1

Cependant, pour GCC et Clang, utiliser <=> <=> devient simplement

<*>

Cela montre donc une fois de plus que <=> est un sous-ensemble de <=> et que lorsque vous utilisez un modèle à virgule flottante plus souple qui n'a pas <=> ou signé zéro, alors <=> et <=> sont identiques . Le même argument s'applique évidemment à <=> et à <=>.

Vous manquez le point entier de fmin et fmax. Il a été inclus dans C99 afin que les processeurs modernes puissent utiliser leurs instructions natives (lire SSE) pour virgule flottante min et max et éviter un test et une branche (et donc une branche éventuellement mal prédite). J'ai réécrit le code qui utilisait std :: min et std :: max pour utiliser les composants intrinsèques de SSE pour les boucles intérieures min et max et la vitesse d'accélération était significative.

std :: min et std :: max sont des modèles. Donc, ils peuvent être utilisés sur une variété de types qui fournissent le moins que l'opérateur, y compris les flotteurs, les doubles, les doubles longs. Donc, si vous voulez é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
}

En ce qui concerne les performances, je ne pense pas que fmin et fmax diffèrent de leurs homologues C ++.

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, qui auront (du moins généralement) une signification inférieure à 64 bits. Lorsque vous convertissez un tel nombre en un double, certains des bits les moins significatifs peuvent être / seront complètement perdus.

Cela signifie que deux nombres vraiment différents peuvent être égaux lorsqu’ils sont convertis en double. Le résultat sera ce nombre incorrect, qui ne correspondra pas nécessairement à l’une des entrées originales.

Je préférerais les fonctions C ++ min / max, si vous utilisez C ++, car elles sont spécifiques au type. fmin / fmax forcera tout à être converti en / à virgule flottante.

De plus, les fonctions C ++ min / max fonctionneront avec des types définis par l'utilisateur tant que vous aurez défini l'opérateur < pour ces types.

HTH

Comme vous l'avez noté vous-même, fmin et fmax ont été introduits dans C99. La bibliothèque C ++ standard n’a pas les fonctions std::min et std::max. Jusqu'à ce que la bibliothèque standard C99 soit incorporée à C ++ (si jamais), les domaines d'application de ces fonctions sont clairement séparés. Il n’ya pas de situation où vous pourriez devoir & «Préférer &»; l'un sur l'autre.

Vous utilisez simplement les modèles <=> / <=> en C ++ et utilisez tout ce qui est disponible en C.

Comme l'a souligné Richard Corden, utilisez les fonctions C ++ min et max définies dans l'espace de noms std. Ils fournissent une sécurité de type et évitent de comparer des types mélangés (c'est-à-dire un nombre à virgule flottante à un nombre entier), ce qui peut parfois être indésirable.

Si vous trouvez que la bibliothèque C ++ que vous utilisez définit également les macros min / max, cela peut également entraîner des conflits, vous pouvez alors empêcher la substitution de macros non souhaitée en appelant les fonctions min / max de cette manière (remarquez les crochets supplémentaires):

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

N'oubliez pas que cela désactivera Recherche dépendante de l'argument (ADL, également appelée recherche Koenig). , au cas où vous voudriez vous fier aux ADL.

fmin et fmax ne sont valables que pour les variables à virgule flottante et double.

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

Utilisez std::min et std::max.

Si les autres versions sont plus rapides, votre implémentation peut ajouter des surcharges 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);
}    

Au fait, dans cstdlib, il y a __min et __max vous pouvez utiliser.

Pour en savoir plus: http://msdn.microsoft.com/zh-cn /library/btkhtd8d.aspx

Une implémentation C ++ destinée aux processeurs avec des instructions SSE ne pouvait-elle pas fournir les spécialisations de std :: min et std :: max pour les types float , double et long double , équivalant à fminf , fmin et fminl , respectivement?

Les spécialisations fourniraient de meilleures performances pour les types à virgule flottante, tandis que le modèle général gérera les types à virgule non flottante sans tenter de contraindre les types à virgule flottante à des types à virgule flottante de la manière fmin . s et fmax es.

J'utilise toujours les macros min et max pour ints. Je ne sais pas pourquoi quelqu'un utiliserait fmin ou fmax pour les valeurs entières.

Le gros problème avec min et max est qu’elles 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 telle, il est recommandé dans mon organisation de ne jamais appeler min ou max avec des éléments qui ne sont ni littéraux ni variables.

fmin et fmax, de fminl et fmaxl pourraient être préférés lorsque vous comparez des entiers signés et non signés - vous pouvez tirer parti du fait que toute la gamme de nombres signés et non signés et avoir à se soucier des plages entières et des promotions.

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

int z = min(x, y);
z = (int)fmin(x, y);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top