Quand est-ce que j'utilise fabs et quand est-il suffisant d'utiliser std :: abs?

100

Je suppose que abset je me fabscomporte différemment lors de l'utilisation math.h. Mais quand j'utilise juste cmathet std::abs, dois-je utiliser std::fabsou fabs? Ou n'est-ce pas défini?

math
la source

Réponses:

124

En C ++, il suffit toujours d'utiliser std::abs; il est surchargé pour tous les types numériques.

En C, absne fonctionne que sur les entiers et vous avez besoin fabsde valeurs à virgule flottante. Ceux-ci sont disponibles en C ++ (avec toute la bibliothèque C), mais il n'est pas nécessaire de les utiliser.

Mike Seymour
la source
Est-ce le cas sur toutes les plateformes? Esp. Windows et Mac OS X? Ou est-ce au moins dans la norme C ++?
math
3
@brubelsabs: oui. Il n'y a pas besoin d'une fonction fabs séparée en C ++ puisque C ++ a une surcharge de fonction (abs peut être défini pour de nombreux types et il est en C ++). Il est également garanti par la norme. Bien sûr, si vous cherchez un compilateur obsolète de plus de 10 ans, vous pourriez en trouver un qui ne le prend pas en charge.
stinky472
1
Il est dans la norme C ++, il est donc le cas sur chaque plate - forme avec un compilateur décent, y compris Windows et Mac OS X. article 26.5 dit que, en plus de la intversion à partir de la bibliothèque C, il y a des surcharges pour long, float, doubleet long double. Le paragraphe 26.2.7 définit également une surcharge pour complex.
Mike Seymour
6
Si vous oubliez std::et utilisez simplement abs, votre code fonctionnera comme prévu sur Windows mais utilisera la intversion sous Linux, ce qui peut être incroyablement difficile à déboguer.
Adversus
" tous les types numériques" [citation nécessaire]. Je peux voir int, long, long long, std :: intmax_t, float, double, long double. Aucune version courte ou char (ou version non signée) que je peux voir.
user673679
23

Il est toujours possible d'utiliser fabspour doubleet des floatarguments. Je préfère cela car cela garantit que si j'enlève accidentellement std::le abs, que le comportement reste le même pour les entrées à virgule flottante.

Je viens de passer 10 minutes à déboguer ce problème même, à cause de ma propre erreur d'utiliser absau lieu de std::abs. J'ai supposé que le using namespace std;serait en déduire, std::absmais ce n'est pas le cas, et j'utilisais plutôt la version C.

Quoi qu'il en soit, je pense qu'il est bon d'utiliser fabsau lieu de abspour les entrées en virgule flottante comme moyen de documenter clairement votre intention.

Alan Turing
la source
2
C'est bizarre. Votre appel aurait dû être ambigu (et donc une erreur) non?
Nick
Ne devriez-vous pas utiliser fabsf pour float? Donc je ne pense pas qu'ils soient identiques.
Nick
Méfiez-vous d'Android NDK g ++, il cède également à la fonction c abs () au lieu de std :: abs (). Cependant, dans le compilateur Visual Studio c ++, abs pointe toujours vers std :: abs ().
Southerton
@Nick, je pense que je suis d'accord avec vous: je ne semble pas comprendre ce comportement d'Alan Turing c'est-à-dire que pour moi, la surcharge std::abssemble toujours être invoquée (et non la version C de abs) lors de l'appel abstant que cela using namespace std;est expliqué au début. Je ne sais pas si c'est spécifique au compilateur.
MaviPranav
@Nick n'est pas une erreur car il y a un nom de fonction qui correspond. C'est la mise en œuvre définie qui sera choisie.
Pato Sandaña
11

Il y a une autre raison de recommander std::fabsexplicitement les entrées à virgule flottante.

Si vous oubliez d'inclure <cmath>, vous std::abs(my_float_num)pouvez être à la std::abs(int)place de std::abs(float). C'est difficile à remarquer.

Kenichi Hidai
la source
1

"abs" et "fabs" ne sont identiques que pour les types float C ++, lorsqu'ils peuvent être traduits sans messages de surcharge ambigus.

J'utilise g ++ (g ++ - 7). Avec l'utilisation de modèles et en particulier lors de l'utilisation de mpreal, il y a des cas avec des messages de «surcharge ambiguë» durs - ce abs(static_cast<T>(x))n'est pas toujours le cas. Lorsque les abdos sont ambigus, il y a des chances que les fabs fonctionnent comme prévu. Pour sqrt, je n'ai trouvé aucune évasion aussi simple.

Depuis des semaines, je me bats dur sur C ++ "problèmes non existants". Je mets à jour un ancien programme C ++ vers C ++ 14 pour une meilleure utilisation des modèles qu'auparavant. Souvent, le même paramètre de modèle peut être un type flottant ou complexe standard ou un type de classe. Pourquoi jamais, long double a agi un peu plus sensible que les autres types. Tout fonctionnait, et j'avais déjà inclus mpreal. Ensuite, je définissais mon type float par défaut sur mpreal et j'ai eu un déluge d'erreurs de syntaxe. Cela a donné des milliers de surcharges ambiguës, par exemple pour les abdos et les sqrt, pleurant pour des solutions différentes. Certains avaient besoin de fonctions d'aide surchargées, mais en dehors d'un modèle. A dû remplacer individuellement un millier d'utilisations de 0.0L et 1.0L par le type de constante exact en utilisant Zero ou One ou un type_cast - définition de conversion automatique impossible en raison d'ambiguïtés.

Jusqu'en mai, j'ai trouvé très agréable l'existence des conversions implicites. Mais beaucoup plus simple ce serait sans aucun, et avoir des constantes de type enregistrer avec des types explicites sûrs dans n'importe quel autre type de constante standard.

BS3
la source