2016-06-01 11 views
4

Ich muss normalisierte Integer-Werte in und von realen Gleitkommawerten konvertieren. Für int16_t wird beispielsweise ein Wert von 1,0 durch 32767 und -1,0 durch -32768 dargestellt. Obwohl es für jeden Integer-Typ, sowohl mit Vorzeichen als auch ohne Vorzeichen, etwas mühsam ist, ist es immer noch einfach, von Hand zu schreiben.Normalisierte Ganzzahl zu/von Float-Konvertierung

Ich möchte jedoch, wann immer möglich, Standardmethoden verwenden, anstatt das Rad neu zu erfinden, also suche ich nach einem Standard-C- oder C++ - Header, einer Boost-Bibliothek oder einem anderen kleinen tragbaren Gerät , leicht einzubindende Quelle, die diese Konvertierungen bereits durchführt.

+1

Ich bin nicht sicher, dass eine Bibliothek benötigt wird ... 'double convert (int16_t x) {return x <0? x/double (32768): x/double (32767);} '. Es kann leicht mit Hilfe von 'std :: numeric_limits' für alle int-Typen als Vorlagen erstellt und verallgemeinert werden. Jedenfalls ist es sehr kurz zu machen und sicherlich nicht in der Standardbibliothek. Schau auch hier: http://stackoverflow.com/questions/929103/convert-a-number-range-on-another-range-maintaining-ratio – coyotte508

+1

@ coyotte508 Obwohl ich es noch nicht gefunden habe, habe ich wirklich gesucht/Ich hoffe auf etwas, das bereits getempert wurde, wie zB std :: numeric_limits in der Standard-Bibliothek, das tut das schon, weil ich weiß, dass ich nicht die Einzige bin, die das braucht. Ich habe so viel von meiner Karriere damit verbracht, Code zu schreiben, der bereits standardisiert sein konnte und sollte, um später herauszufinden, dass jemand _bereits_ geschrieben hatte, dass ich in diesen Tagen versuche, existierenden, standardisierten Code zu finden, bevor ich ihn selbst schreibe. BTW, danke für den Link. – IntellectualKitty

+1

Ich würde normalerweise zustimmen, aber wenn es eine Zeile ist, ist es klarer, es "inline" (vor Ort) zu haben, als in einen obskuren Namen-Funktionsaufruf von Möchtegern-Standard verpackt. Übrigens, orthogonal zur Frage, willst du wirklich Floats benutzen? Die Genauigkeit variiert enorm im Bereich zwischen 0 und 1. –

Antwort

6

Hier ist eine Templat-Lösung mit std::numeric_limits:

#include <cstdint> 
#include <limits> 

template <typename T> 
constexpr double normalize (T value) { 
    return value < 0 
    ? -static_cast<double>(value)/std::numeric_limits<T>::min() 
    : static_cast<double>(value)/std::numeric_limits<T>::max() 
    ; 
} 

int main() { 
    // Test cases evaluated at compile time. 
    static_assert(normalize(int16_t(32767)) == 1, ""); 
    static_assert(normalize(int16_t(0)) == 0, ""); 
    static_assert(normalize(int16_t(-32768)) == -1, ""); 
    static_assert(normalize(int16_t(-16384)) == -0.5, ""); 
    static_assert(normalize(uint16_t(65535)) == 1, ""); 
    static_assert(normalize(uint16_t(0)) == 0, ""); 
} 

Diese Griffe sowohl mit und ohne Vorzeichen ganzen Zahlen und 0 nicht normalisieren auf 0.

View Successful Compilation Result

+1

Das ist ein sehr netter Code und ein guter Anwendungsfalltest. Vielen Dank. – IntellectualKitty

+1

Konvertieren von Integer in Double ist einfach genug, aber es wäre schön, auch eine korrekte Lösung zu sehen, um von Double zu Integer zu gehen (dh wo 0.99999999999 == 32767 statt 0.99999999999 == 32766) wie bei der Verwendung ein ähnlicher Ansatz in dieser Richtung von 'static_cast (Wert * std :: numeric_limits :: max()' aufgrund der Art, wie static_cast truncates eher als Runden. –

-2

Obwohl es ein bisschen langweilig ist das für jeden Integer-Typen zu tun, sowohl mit und ohne Vorzeichen, es ist immer noch leicht genug, um mit der Hand zu schreiben.

Sie müssen dies sicherlich nicht für jeden Integer-Typ tun! Verwenden Sie stattdessen <limits>.

template<class T> double AsDouble(const T x) { 
    const double valMin = std::numeric_limits<T>::min(); 
    const double valMax = std::numeric_limits<T>::max(); 
    return 2 * (x - valMin)/(valMax - valMin) - 1; // note: 0 does not become 0. 
}