2013-03-15 17 views
6

W C++, załóżmy, że mam numer x typu T, który może być typem całkowitym lub zmiennoprzecinkowym. Chcę znaleźć największy numer y typu T, dla którego jest przechowywany y < x. Rozwiązanie musi być szablonowe, aby działało w sposób przezroczysty zarówno dla liczb całkowitych, jak i liczb zmiennoprzecinkowych. Możesz zignorować przypadek krawędzi, gdzie x jest już najmniejszą liczbą, która może być reprezentowana w T.Największa liczba <x?

ewentualnego wykorzystania CASE: To pytanie zostało oznaczone jako zbyt zlokalizowane, stąd chciałbym zapewnić przypadek użycia, który moim zdaniem jest bardziej ogólne. Zauważ, że nie jestem oryginalnym autorem OP.

Rozważmy następujący wzór:

struct lower_bound { 
    lower_bound(double value, bool open) : value(open? value+0.1 : value) {} 
    double value; 
    bool operator()(double x) { return x >= value; } 
}; 

Klasa symuluje dolnej granicy, która może być albo otwarte albo zamknięte. Oczywiście w rzeczywistym (kalamburowym) życiu nie możemy tego zrobić. Przepływ jest niemożliwy (lub przynajmniej dość trudny) do obliczenia dla S będąc wszystkimi liczbami rzeczywistymi.

enter image description here

Jednak gdy S jest zbiorem liczb zmiennoprzecinkowych, jest to bardzo ważna zasada, ponieważ mamy do czynienia z zasadniczo na zbiór przeliczalny; a następnie nie ma czegoś takiego jak otwarta lub zamknięta granica. Oznacza to, że> = można zdefiniować w kategoriach> like done w klasie lower_bound.

Dla uproszczenia kodu użyłem +0.1 do symulacji otwartej dolnej granicy. Oczywiście 0,1 jest wartością surową, ponieważ mogą występować wartości z takie, że wartość jest równa < z < = wartość + 0,1 lub wartość + 0,1 == wartość reprezentacji zmiennoprzecinkowej. Stąd @ ​​Brett-hale Odpowiedź jest bardzo przydatna :)

Możesz pomyśleć o innym prostsze rozwiązanie:

struct lower_bound { 
    lower_bound(double value, bool open) : open(open), value(value) {} 
    bool open; 
    double value; 
    bool operator()(double x) { return (open ? x > value : x>=value); } 

}; 

Jest to jednak mniej skuteczne jako sizeof (LOWER_BOUND) jest większa, i operator() musi wykonać bardziej skomplikowaną instrukcję. Pierwsza implementacja jest naprawdę wydajna i może być implementowana po prostu jako podwójna, a nie jako struktura. Z technicznego punktu widzenia jedynym powodem skorzystania z drugiej implementacji jest to, że zakłada się, że podwójne jest ciągłe, podczas gdy nie jest i wydaje mi się, że nie będzie nigdzie w najbliższej przyszłości.

Mam nadzieję, że stworzyłem i wyjaśniłem ważny przypadek użycia i że nie obraziłem pierwotnego autora.

+1

można dać przykład, co byłoby dla pływających typy punktów? Czy to oznacza, że ​​mantyka y jest mniejsza o jeden bit, a wykładnik jest taki sam? – angelatlarge

+3

Oczekuję więcej od użytkownika 27,5 tys. –

+0

Czy ... próbowałeś czegoś? – Rapptz

Odpowiedz

11

Jeśli masz C++ 11, można użyć std::nextafter w <cmath>:

if (std::is_integral<T>::value) 
    return (x - 1); 
else 
    return std::nextafter(x, - std::numeric_limits<T>::infinity()); 
+0

[x-1.0 może być równe x dla typów zmiennoprzecinkowych i zdarza się dla wielu wielu liczb = = 33554432] (http : //coliru.stacked-crooked.com/view? id = cc0ae3f34df4c559275ba1290458f077-61c3814520a8d4318f681038dc4b4da7) –

+0

@MooingDuck - tak, dziękuję.To było pochopne. błąd ute. –

+0

@BrettHale: Łatwy nadzór, jestem pewien, że to także mój kod. –

Powiązane problemy