2008-10-09 8 views
20

Was ist in C++ die allgemeine Möglichkeit, einen Gleitkommawert (Gleitkommazahl) in fixed point (int, 16:16 oder 24: 8) zu konvertieren?Konvertieren von Fließkomma in Fixpunkt

EDIT: Zur Klarstellung, Festpunkt Werte haben zwei Teile zu ihnen: ein ganzzahliger Teil und ein Bruchteil. Der ganzzahlige Teil kann durch einen ganzzahligen Datentyp mit Vorzeichen oder ohne Vorzeichen dargestellt werden. Der Bruchteil wird durch einen vorzeichenlosen Ganzzahldatentyp dargestellt.

Lassen Sie uns aus Gründen der Klarheit eine Analogie mit Geld machen. Der Bruchteil kann Cents darstellen - ein Bruchteil eines Dollars. Der Bereich des Datentyps "Cents" würde 0 bis 99 betragen. Wenn eine 8-Bit-Ganzzahl ohne Vorzeichen für die Festkomma-Mathematik verwendet würde, würde der Bruchteil in 256 gleichmäßig teilbare Teile aufgeteilt.

Ich hoffe, dass die Dinge klären.

+0

Wenn Sie in Visual C++ sind, experimentieren Sie mit dem '/ fp: fast'-Schalter, bevor Sie überhaupt daran denken, Ihren gesamten Fließkommawert auf einen festen Punkt zu bringen. Dieser Gleitkomma-Modellschalter ermöglicht Optimierungen, die es einem Gleitkomma ermöglichen, einen festen Punkt in der Geschwindigkeit leicht zu übertreffen. Definitiv ein unterschätztes Merkmal. –

Antwort

26

Hier gehen Sie:

// A signed fixed-point 16:16 class 
class FixedPoint_16_16 
{ 
    short   intPart; 
    unsigned short fracPart; 

public: 
    FixedPoint_16_16(double d) 
    { 
     *this = d; // calls operator= 
    } 

    FixedPoint_16_16& operator=(double d) 
    { 
     intPart = static_cast<short>(d); 
     fracPart = static_cast<unsigned short> 
        (numeric_limits<unsigned short> + 1.0)*d); 
     return *this; 
    } 

    // Other operators can be defined here 
}; 

EDIT: Hier ist eine allgemeine Klasse auf anothercommon Art und Weise basierend mit Festpunktzahlen zu behandeln (und die KPexEA darauf hingewiesen):

template <class BaseType, size_t FracDigits> 
class fixed_point 
{ 
    const static BaseType factor = 1 << FracDigits; 

    BaseType data; 

public: 
    fixed_point(double d) 
    { 
     *this = d; // calls operator= 
    } 

    fixed_point& operator=(double d) 
    { 
     data = static_cast<BaseType>(d*factor); 
     return *this; 
    } 

    BaseType raw_data() const 
    { 
     return data; 
    } 

    // Other operators can be defined here 
}; 


fixed_point<int, 8> fp1;   // Will be signed 24:8 (if int is 32-bits) 
fixed_point<unsigned int, 16> fp1; // Will be unsigned 16:16 (if int is 32-bits) 
+3

Dies ist mehr über das Sezieren einer Gleitkommazahl, anstatt sie in eine Festkommadarstellung zu konvertieren. – Trap

+1

numeric_limits ** :: ???? ** Ich glaube, da fehlt ein Teil. – Ant

+3

Was ist "DataType" hier? Wo ist das definiert? – dicroce

0

Dies ist in Ordnung für die Konvertierung von Gleitkommazahl in Ganzzahl, aber das OP wollte auch fixed point.

Nun, wie Sie das in C++ tun würden, weiß ich nicht (C++ ist nicht etwas, woran ich schnell denken kann). Versuchen Sie vielleicht einen skalierten Ganzzahl-Ansatz, d. H. Verwenden Sie eine 32- oder 64-Bit-Ganzzahl und ordnen Sie programmatisch die letzten, sagen wir, 6 Ziffern dem zu, was sich auf der rechten Seite des Dezimalpunkts befindet.

18

Ein Cast von float nach integer wird den Bruchteil wegwerfen. Wenn Sie also diesen Bruchteil als Fixpunkt behalten wollen, multiplizieren Sie einfach den float, bevor Sie ihn werfen. Der unten stehende Code prüft nicht auf Überlauf.

Wenn Sie 16:16

double f = 1.2345; 
int n; 

n=(int)(f*65536); 

, wenn Sie 24 wollen: 8

double f = 1.2345; 
int n; 

n=(int)(f*256); 
-4

Es gibt keine Unterstützung in C++ gebaut für Festpunktzahlen. Am besten wäre es, eine Wrapper-Klasse "FixedInt" zu schreiben, die Doubles akzeptiert und sie konvertiert.

Wie für eine generische Methode zu konvertieren ... der Int-Teil ist einfach genug, greifen Sie einfach den ganzzahligen Teil des Wertes und speichern Sie es in den oberen Bits ... Dezimal Teil wäre etwas in den folgenden Linien:

for (int i = 1; i <= precision; i++) 
{ 
    if (decimal_part > 1.f/(float)(i + 1) 
    { 
     decimal_part -= 1.f/(float)(i + 1); 
     fixint_value |= (1 << precision - i); 
    } 
} 

obwohl dies wahrscheinlich Fehler enthalten noch

6

**** Bearbeiten **: Mein erster Kommentar gilt vor Kevins bearbeiten, aber ich werde es hier für die Nachwelt hinterlassen. Die Antworten ändern sich hier manchmal so schnell!

Das Problem mit Kevins Ansatz ist, dass Sie mit Fixed Point normalerweise in eine garantierte Wortgröße packen (normalerweise 32 Bit). Wenn Sie die beiden Teile separat deklarieren, können Sie die Struktur des Compilers strukturieren. Ja, Sie könnten es erzwingen, aber es funktioniert nicht für etwas anderes als 16:16 Darstellung.

KPexEA ist näher an der Marke durch Packen alles in int - obwohl ich "signed long" verwenden würde, um zu versuchen, und explizit auf 32Bits sein. Dann können Sie seinen Ansatz verwenden, um den Fixpunktwert zu generieren, und das Bit-Slicing extrahiert die Komponenten erneut. Sein Vorschlag deckt auch den 24: 8-Fall ab.

(Und alle anderen, die nur static_cast vorgeschlagen ..... was Sie denken;))

1

ich die Antwort auf den Mann gab, der die beste Antwort schrieb, aber ich habe wirklich einen ähnlichen Code Fragen das zeigt here.

Es verwendete Vorlagen und war leicht Abhängigkeiten von der Boost-Lib Graben.

+0

der Link ist gebrochen (404) –

+0

Es wäre besser, die verwandte Frage das nächste Mal zu verknüpfen. Wie Ivan über mich durch das Kommentieren deutlich gemacht hat, bleiben Fragen relevant. Diese Antwort enthält keine Informationen mehr. –

Verwandte Themen