Comment initialiser un flottant à sa valeur max / min?

100

Comment coder en dur une valeur maximale ou minimale absolue pour un flottant ou un double? Je veux rechercher le max / min d'un tableau en itérant simplement et en capturant le plus grand.

Il existe également une infinité positive et négative pour les flottants, dois-je les utiliser à la place? Si tel est le cas, comment le désigner dans mon code?

Faux
la source

Réponses:

152

Vous pouvez utiliser std::numeric_limitsce qui est défini dans <limits>pour trouver la valeur minimale ou maximale des types (tant qu'il existe une spécialisation pour le type). Vous pouvez également l'utiliser pour récupérer l'infini (et mettre un -devant pour l'infini négatif).

#include <limits>

//...

std::numeric_limits<float>::max();
std::numeric_limits<float>::min();
std::numeric_limits<float>::infinity();

Comme indiqué dans les commentaires, min()renvoie la valeur positive la plus basse possible. En d'autres termes, la valeur positive la plus proche de 0 qui peut être représentée. La valeur la plus basse possible est la valeur négative de la valeur maximale possible.

Il y a bien sûr les std::max_elementfonctions et min_element (définies dans <algorithm>) qui peuvent être un meilleur choix pour trouver la valeur la plus grande ou la plus petite d'un tableau.

Yacoby
la source
Comment l'utiliser exactement? Que dois-je inclure? Je ne pense pas avoir utilisé quelque chose comme ça avant.
Faken le
Hmm ... cette fonction d'élément max aurait été très utile ... c'est ce qui se passe lorsque vous apprenez le codage par vous-même et pas formellement. Vous finissez par réinventer la roue 50 fois. C'est comme la dernière fois que j'ai découvert ceil (). Je vous remercie.
Faken le
18
@Yacoby, vous voudrez peut-être préciser que numeric_limits <float> :: min () ne signifie pas la valeur la plus négative, mais la plus petite positive.
MSN
13
@killogre: C ++ 11 ajouté numeric_limits<T>::lowest(), qui renvoie la valeur la plus basse (négative) possible pour le type pour résoudre ce problème.
Cornstalks
3
std::numeric_limits<float>::min()ne donne pas la plus petite valeur positive qui puisse être représentée; il donne le plus petit nombre normal à virgule flottante simple précision. Il existe également des nombres inférieurs à la normale entre zéro et ce nombre. En particulier, std::numeric_limits<float>::min()donne 1.17549e-38mais le plus petit flotteur subnormal représentable est nextafterf(0.0f, 1.0f) == 1.4013e-45f.
nibot
45

Vous pouvez utiliser -FLT_MAX(ou -DBL_MAX) pour le nombre négatif de magnitude maximale et FLT_MAX(ou DBL_MAX) pour le positif. Cela vous donne la plage de valeurs flottantes (ou doubles) possibles.

Vous ne voulez probablement pas utiliser FLT_MIN; il correspond au plus petit nombre positif de magnitude pouvant être représenté avec un flottant, et non à la valeur la plus négative représentable avec un flottant.

FLT_MINet FLT_MAXcorrespondent à std::numeric_limits<float>::min()et std::numeric_limits<float>::max().

MSN
la source
Je pense que je vais utiliser cette version en fait, elle est plus simple à retenir et me fait plus de scène. Entiers que je peux simplement initialiser en utilisant hexadécimal. Cependant, la meilleure réponse reste car la réponse m'a également présenté de nouvelles fonctions extrêmement utiles.
Faken le
2
"[ FLT_MIN] correspond au plus petit nombre positif de magnitude qui peut être représenté avec un flotteur" - Ce n'est pas vrai . C'est le plus petit nombre normal . Il existe également des nombres inférieurs à la normale.
nibot
Vous voulez FLT_TRUE_MINle plus petit flotteur possible, ce qui correspond àstd::numeric_limits<float>::denorm_min()
Chris Dodd
17

Il n'y a pas vraiment besoin de s'initialiser au plus petit / plus grand possible pour trouver le plus petit / le plus grand du tableau:

double largest = smallest = array[0];
for (int i=1; i<array_size; i++) {
    if (array[i] < smallest)
        smallest = array[i];
    if (array[i] > largest0
        largest= array[i];
}

Ou, si vous le faites plus d'une fois:

#include <utility>

template <class iter>
std::pair<typename iter::value_type, typename iter::value_type> find_extrema(iter begin, iter end) {
    std::pair<typename iter::value_type, typename iter::value_type> ret;
    ret.first = ret.second = *begin;
    while (++begin != end) {
        if (*begin < ret.first)
           ret.first = *begin;
        if (*begin > ret.second)
           ret.second = *begin;
   }
   return ret;
}

L'inconvénient de fournir un exemple de code - je vois que d'autres ont déjà suggéré la même idée.

Notez que bien que la norme ait un min_element et un max_element, leur utilisation nécessiterait de parcourir les données deux fois, ce qui pourrait poser un problème si le tableau est grand. Des normes récentes ont résolu ce problème en ajoutant un std::minmax_element, qui fait la même chose que find_extremaci - dessus (trouvez à la fois les éléments minimum et maximum dans une collection en un seul passage).

Edit: Résoudre le problème de la recherche de la plus petite valeur non nulle dans un tableau de unsigned: observez que les valeurs non signées «s'enroulent» lorsqu'elles atteignent un extrême. Pour trouver la plus petite valeur non nulle, nous pouvons soustraire une de chacune pour la comparaison. Toute valeur nulle sera "enveloppée" à la plus grande valeur possible pour le type, mais la relation entre les autres valeurs sera conservée. Une fois que nous avons terminé, nous en rajoutons évidemment un à la valeur que nous avons trouvée.

unsigned int min_nonzero(std::vector<unsigned int> const &values) { 
    if (vector.size() == 0)
        return 0;
    unsigned int temp = values[0]-1;
    for (int i=1; i<values.size(); i++)
        if (values[i]-1 < temp)
            temp = values[i]-1;
    return temp+1;
}

Notez que cela utilise toujours le premier élément pour la valeur initiale, mais nous n'avons toujours pas besoin de code de «cas spécial» - puisque cela se terminera par la plus grande valeur possible, toute valeur non nulle sera comparée comme étant plus petite. Le résultat sera la plus petite valeur différente de zéro, ou 0 si et seulement si le vecteur ne contient aucune valeur différente de zéro.

Jerry Coffin
la source
Mais vous obtenez un +1 de ma part!
Dan Diplo
1
Je commence à max minutes parce que parfois je veux la plus petite valeur non nulle (dans un cas entier non signé par exemple, mes données ont tendance à avoir beaucoup de zéros inintéressants). Il me semble juste logique de l'initialiser plutôt que d'effectuer des vérifications supplémentaires pour s'assurer que le premier élément n'est pas nul.
Faken le
@Faken: Même dans ce cas, vous pouvez définir une fonction de comparaison qui traite zéro comme la plus grande valeur possible, vous pouvez donc toujours utiliser std::min_element:bool less_ignoring_zero(unsigned a, unsigned b) { if (a == 0) return false; if (b == 0) return true; return a < b; }
UncleBens
2
@Jerry: C ++ 0x ajoutera minmax_element pour résoudre le problème que vous mentionnez. (Mais alors il ne sera pas possible d'ignorer les zéros ...)
UncleBens
1
Que faire si le premier élément n'est pas disponible au moment de l'initialisation? Cela se produit beaucoup dans le traitement en ligne (comme dans boost :: accumulators)
killogre
5

Pour trouver manuellement le minimum d'un tableau, vous n'avez pas besoin de connaître la valeur minimum de float:

float myFloats[];
...
float minimum = myFloats[0];
for (int i = 0; i < myFloatsSize; ++i)
{
  if (myFloats[i] < minimum)
  {
    minimum = myFloats[i];
  }
}

Et un code similaire pour la valeur maximale.

Facture
la source
4

Puis-je vous suggérer d'initialiser vos variables "max et min jusqu'ici" non pas à l'infini, mais au premier nombre du tableau?

Thomas Padron-McCarthy
la source