jak zainicjować wartość zmiennoprzecinkową do wartości maksymalnej / minimalnej?


100

Jak zakodować bezwzględną wartość maksymalną lub minimalną dla liczby zmiennoprzecinkowej lub podwójnej? Chcę wyszukać maks / min tablicy, po prostu przechodząc przez iterację i przechwytując największą.

Istnieje również dodatnia i ujemna nieskończoność dla pływaków, czy powinienem ich użyć zamiast tego? Jeśli tak, jak mam to oznaczyć w moim kodzie?

Odpowiedzi:


152

Możesz użyć tego, std::numeric_limitsktóry jest zdefiniowany w, <limits>aby znaleźć minimalną lub maksymalną wartość typów (o ile istnieje specjalizacja dla typu). Możesz także użyć go do odzyskania nieskończoności (i wstaw -przed siebie ujemną nieskończoność).

#include <limits>

//...

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

Jak zauważono w komentarzach, min()zwraca najniższą możliwą wartość dodatnią. Innymi słowy, wartość dodatnia najbliższa 0, którą można przedstawić. Najniższa możliwa wartość jest ujemną wartością maksymalnej możliwej wartości.

Istnieją oczywiście funkcje std::max_elementi min_element (zdefiniowane w <algorithm>), które mogą być lepszym wyborem do znalezienia największej lub najmniejszej wartości w tablicy.


Jak dokładnie tego używać? Co muszę dołączyć? Chyba nie użyłem czegoś takiego wcześniej.
Faken

Hmm ... ta funkcja max elementu byłaby bardzo przydatna ... tak się dzieje, gdy uczysz się kodowania samodzielnie, a nie formalnie. W końcu wymyślasz koło na nowo 50 razy. To tak, jak ostatnio, gdy dowiedziałem się o ceil (). Dziękuję Ci.
Faken

18
@Yacoby, możesz chcieć wyjaśnić, że numeric_limits <float> :: min () nie oznacza najbardziej ujemnej wartości, oznacza najmniejszą dodatnią.
MSN

13
@killogre: dodano C ++ 11 numeric_limits<T>::lowest(), który zwraca najniższą (ujemną) wartość możliwą do rozwiązania tego problemu przez typ.
Cornstalks

3
std::numeric_limits<float>::min()sposób nie da najmniejszą wartość dodatnią, który może być reprezentowany; daje najmniejszą normalną liczbę zmiennoprzecinkową o pojedynczej precyzji. Istnieją również liczby podnormalne od zera do tej liczby. W szczególności std::numeric_limits<float>::min()daje, 1.17549e-38ale najmniejszą reprezentowalną wartością zmiennoprzecinkową jest nextafterf(0.0f, 1.0f) == 1.4013e-45f.
nibot

45

Możesz użyć -FLT_MAX(lub -DBL_MAX) dla maksymalnej liczby ujemnej wielkości i FLT_MAX(lub DBL_MAX) dla wartości dodatniej. Daje to zakres możliwych wartości zmiennoprzecinkowych (lub podwójnych).

Prawdopodobnie nie chcesz używać FLT_MIN; odpowiada najmniejszej dodatniej liczbie wielkości, którą można przedstawić za pomocą liczby zmiennoprzecinkowej, a nie najbardziej ujemnej wartości reprezentowanej przez zmiennoprzecinkę.

FLT_MINi FLT_MAXodpowiadają std::numeric_limits<float>::min()i std::numeric_limits<float>::max().


Myślę, że faktycznie użyję tej wersji, jest prostsza do zapamiętania i tworzy dla mnie więcej scen. Liczby całkowite, które mogę po prostu zainicjować, używając szesnastkowej. Jednak najlepsza odpowiedź wciąż pozostaje, ponieważ dzięki niej poznałem również kilka nowych, niezwykle przydatnych funkcji.
Faken

2
„[ FLT_MIN] odpowiada najmniejszej dodatniej liczbie wielkości, którą można przedstawić za pomocą liczby zmiennoprzecinkowej” - to nieprawda . To najmniejsza normalna liczba. Istnieją również liczby poniżej normy.
nibot

Chcesz FLT_TRUE_MINdla rzeczywistego najmniejszego możliwego pływaka, który odpowiadastd::numeric_limits<float>::denorm_min()
Chris Dodd

17

Nie ma rzeczywistej potrzeby inicjalizacji do najmniejszej / największej możliwej wartości, aby znaleźć najmniejszą / największą w tablicy:

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

Lub, jeśli robisz to więcej niż raz:

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

Wada podania przykładowego kodu - widzę, że inni już zasugerowali ten sam pomysł.

Zauważ, że chociaż standard ma elementy min_element i max_element, użycie ich wymagałoby dwukrotnego przeskanowania danych, co może być problemem, jeśli tablica jest w ogóle duża. Najnowsze standardy rozwiązały ten problem, dodając a std::minmax_element, co robi to samo, co find_extremapowyżej (znajduje zarówno minimum, jak i maksimum elementów w kolekcji w jednym przebiegu).

Edycja: Rozwiązanie problemu znalezienia najmniejszej niezerowej wartości w tablicy bez znaku: zauważ, że wartości bez znaku „zawijają się”, gdy osiągają ekstremum. Aby znaleźć najmniejszą wartość różną od zera, możemy odjąć po jednym dla porównania. Wszelkie wartości zerowe zostaną „zawinięte” do największej możliwej wartości dla typu, ale relacje między innymi wartościami zostaną zachowane. Po zakończeniu oczywiście dodajemy jeden z powrotem do znalezionej wartości.

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

Zauważ, że nadal używa pierwszego elementu jako wartości początkowej, ale nadal nie potrzebujemy żadnego kodu „specjalnego przypadku” - ponieważ będzie on zawijany do największej możliwej wartości, każda wartość niezerowa zostanie porównana jako mniejsza. Wynikiem będzie najmniejsza wartość niezerowa lub 0 wtedy i tylko wtedy, gdy wektor nie zawiera wartości niezerowych.


Ale dostaniesz za to +1 ode mnie!
Dan Diplo,

1
Initlize to max mins, ponieważ czasami chcę najmniejszej wartości niezerowej (na przykład w przypadku liczby całkowitej bez znaku moje dane mają zwykle wiele nieciekawych zer). Po prostu wydaje mi się sensowne, aby go zainicjować, zamiast przeprowadzać dodatkowe sprawdzenia, aby upewnić się, że pierwszy element nie jest zerowy.
Faken

@Faken: Nawet wtedy możesz zdefiniować funkcję porównawczą, która traktuje zero jako największą możliwą wartość, więc nadal możesz użyć 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 doda minmax_element, aby rozwiązać wspomniany problem. (Ale wtedy nie będzie można ignorować zer ...)
UncleBens

1
A co jeśli pierwszy element nie jest dostępny w momencie inicjalizacji? Dzieje się to często w przetwarzaniu online (jak w boost ::
umulators

5

Aby ręcznie znaleźć minimum tablicy, nie musisz znać minimalnej wartości float:

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

I podobny kod dla maksymalnej wartości.


4

Czy mogę zasugerować, abyś zainicjował swoje zmienne „max i min do tej pory” nie do nieskończoności, ale do pierwszej liczby w tablicy?

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.