bir kayan noktayı maksimum / min değerine nasıl başlatırım?


100

Bir float veya double için mutlak bir maksimum veya minimum değeri nasıl sabit kodlayabilirim? Basitçe yineleyerek ve en büyüğünü yakalayarak bir dizinin maks / min değerini aramak istiyorum.

Float'lar için pozitif ve negatif sonsuzluk vardır, bunun yerine bunları kullanmalı mıyım? Öyleyse, bunu kodumda nasıl ifade ederim?

Yanıtlar:


152

Türlerin minimum veya maksimum değerini bulmak için std::numeric_limitsiçinde tanımlananları kullanabilirsiniz <limits>(Tür için bir uzmanlık olduğu sürece). Sonsuzluğu elde etmek için de kullanabilirsiniz (ve -negatif sonsuzluğun önüne bir koyabilirsiniz ).

#include <limits>

//...

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

Yorumlarda belirtildiği gibi, min()olası en düşük pozitif değeri döndürür. Diğer bir deyişle, 0'a en yakın pozitif değer gösterilebilir. Olası en düşük değer, olası maksimum değerin negatifidir.

Elbette, bir dizideki en büyük veya en küçük değeri bulmak için daha iyi bir seçim olabilecek std::max_elementve min_element işlevleri (içinde tanımlanmıştır <algorithm>) vardır.


Bunu tam olarak nasıl kullanırım? Neleri eklemem gerekiyor? Daha önce böyle bir şey kullandığımı sanmıyorum.
Faken

Hmm ... bu maksimum eleman işlevi çok faydalı olabilirdi ... bu, kodlamayı resmi olarak değil, kendi başınıza öğrendiğinizde olur. Tekerleği 50 kez yeniden icat ediyorsunuz. Bu, ceil () 'i en son öğrendiğim zamanki gibi. Teşekkür ederim.
Faken

18
@Yacoby, numeric_limits <float> :: min () 'in çoğu negatif değer anlamına gelmediğini, en küçük pozitif anlamına geldiğini açıklığa kavuşturmak isteyebilirsiniz.
MSN

13
@killogre: C ++ 11 eklendi numeric_limits<T>::lowest(), bu da türün bu sorunu çözmesi için mümkün olan en düşük (negatif) değeri döndürür.
Cornstalks

3
std::numeric_limits<float>::min()yok değil temsil edilebilir en küçük pozitif değer vermek; en küçük normal tek duyarlıklı kayan nokta numarasını verir. Sıfır ile bu sayı arasında normal altı sayılar da vardır . Özellikle, std::numeric_limits<float>::min()verir 1.17549e-38ancak en küçük gösterilebilir normal altı kayan nokta nextafterf(0.0f, 1.0f) == 1.4013e-45f.
nibot

45

Aşağıdakileri yapabilirsiniz kullanım -FLT_MAX(veya -DBL_MAXmaksimum büyüklüğü negatif bir sayı ve için) FLT_MAX(veya DBL_MAXpozitif için). Bu size olası kayan (veya çift) değer aralığını verir.

Muhtemelen kullanmak istemiyorsunuz FLT_MIN; bir kayan nokta ile temsil edilebilen en negatif değere değil, bir kayan nokta ile temsil edilebilen en küçük büyüklükte pozitif sayıya karşılık gelir.

FLT_MINve FLT_MAXkarşılık gelir std::numeric_limits<float>::min()ve std::numeric_limits<float>::max().


Aslında bu versiyonu kullanacağımı düşünüyorum, hatırlaması daha kolay ve bana daha çok sahne kazandırıyor. Tamsayılar sadece onaltılık kullanarak başlatabilirim. Yine de, en iyi cevap hala geçerli çünkü cevap aynı zamanda beni son derece kullanışlı bazı yeni işlevlerle tanıştırdı.
Faken

2
"[ FLT_MIN], bir kayan nokta ile temsil edilebilecek en küçük büyüklükte pozitif sayıya karşılık gelir" - Bu doğru değil . En küçük normal sayıdır. Ayrıca normal altı sayılar da vardır.
nibot

FLT_TRUE_MINMümkün olan en küçük şamandırayı istiyorsunuz , bu std::numeric_limits<float>::denorm_min()
Chris Dodd

17

Dizideki en küçük / en büyüğü bulmak için mümkün olan en küçüğü / en büyüğü başlatmaya gerçekten gerek yoktur:

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

Veya birden fazla yapıyorsanız:

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

Örnek kod sağlamanın dezavantajı - Başkalarının da aynı fikri önerdiğini görüyorum.

Standart bir min_element ve max_element'e sahipken, bunları kullanmanın veriyi iki kez taramayı gerektireceğini unutmayın; bu, dizi büyükse bir sorun olabilir. Son standartlar std::minmax_element, find_extremayukarıdakilerle aynı şeyi yapan (bir koleksiyondaki hem minimum hem de maksimum öğeleri tek geçişte bulun) ekleyerek bunu ele almıştır .

Düzenleme: Bir işaretsiz dizide sıfır olmayan en küçük değeri bulma sorununu ele almak: işaretsiz değerlerin bir uç noktaya ulaştığında "sardığını" gözlemleyin. Sıfır olmayan en küçük değeri bulmak için, karşılaştırma için her birinden bir tane çıkarabiliriz. Sıfır değerleri, tür için olası en büyük değere "sarılır", ancak diğer değerler arasındaki ilişki korunur. İşimiz bittikten sonra, bulduğumuz değere açıkça bir tane ekliyoruz.

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

Bunun hala başlangıç ​​değeri için ilk öğeyi kullandığına dikkat edin, ancak yine de herhangi bir "özel durum" koduna ihtiyacımız yok - bu, mümkün olan en büyük değere sarılacağından, sıfır olmayan herhangi bir değer daha küçük olarak karşılaştırılacaktır. Sonuç, sıfır olmayan en küçük değer veya ancak ve ancak vektör sıfırdan farklı değerler içermiyorsa 0 olur.


Ama benden +1 alıyorsun!
Dan Diplo

1
Maksimum dakikaya initliyorum çünkü bazen sıfır olmayan en küçük değeri istiyorum (örneğin, işaretsiz bir tamsayı durumunda, verilerim çok fazla ilgi çekici olmayan sıfırlara sahip olma eğilimindedir). İlk elemanın sıfır olmadığından emin olmak için fazladan kontroller yapmaktansa onu başlatmak bana mantıklı geliyor.
Faken

@Faken: O zaman bile sıfırı mümkün olan en büyük değer olarak kabul eden bir karşılaştırma işlevi tanımlayabilirsiniz, böylece yine de kullanabilirsiniz 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, bahsettiğiniz sorunu çözmek için minmax_element ekleyecektir. (Ama o zaman sıfırları görmezden gelmek mümkün olmayacak ...)
UncleBens

1
Ya ilk öğe başlatma sırasında mevcut değilse? Bu, çevrimiçi işlemede çok olur (boost :: akümülatörlerde olduğu gibi)
killogre

5

Bir dizinin minimum değerini manuel olarak bulmak için minimum float değerini bilmenize gerek yoktur:

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

Ve maksimum değer için benzer bir kod.


4

"Şimdiye kadarki max ve min" değişkenlerinizi sonsuza değil, dizideki ilk sayıya başlatmanızı önerebilir miyim?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.