[c++] [selfmade] float zu string konvertieren

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
Benutzeravatar
Goderion
Beiträge: 82
Registriert: 16.09.2012, 12:02

[c++] [selfmade] float zu string konvertieren

Beitrag von Goderion » 19.11.2017, 15:26

Hallo.

Ich versuche gerade einen float in einen string umzuwandeln. Zum Experimentieren und mein Problem besser darzustellen, habe ich folgendes gemacht:

Code: Alles auswählen

int FloatToStringTest(void)
{
	struct StructFloat32
	{
		unsigned int Mantissa : 23;
		unsigned int Exponent : 8;
		unsigned int Sign : 1;
	};

	union UnionFloat32
	{
		float Value;
		StructFloat32 Struct;
	};

	UnionFloat32 Test;
	Test.Value = 234.435f;

	unsigned int Mantissa = Test.Struct.Mantissa + 0x00800000;
	char Exponent = Test.Struct.Exponent - 127;
	char Sign = Test.Struct.Sign;

	if (128 == Exponent)
	{
		if (0 == Mantissa)
		{
			if (0 == Sign)
			{
				// Infinity
			}
			else
			{
				// -Infinity
			}
		}
		else
		{
			// NaN
		}

		return 0;
	}

	if (Exponent >= 23)
	{
		// Problem 1: Überlauf möglich

		unsigned __int64 Integer = Mantissa;
		Integer <<= (Exponent - 23); // Überlauf möglich

		return 0;
	}
	else if (Exponent >= 0)
	{
		// Sollte immer funktionieren?

		unsigned char Shift = 23 - Exponent;
		unsigned __int64 Integer = Mantissa >> Shift;
		unsigned __int64 Fraction = Mantissa - (Integer << Shift);
		unsigned __int64 Divisor = 1ULL << Shift;
		unsigned __int64 Precision = 1000000000;
		unsigned __int64 Float = (Fraction + Divisor) * Precision / Divisor;
		float Check = Fraction / (float)Divisor;

		return 0;
	}
	else
	{
		// Problem 2: Überlauf möglich

		unsigned char Shift = 23 - Exponent;
		Shift = 63;
		unsigned __int64 Fraction = Mantissa;
		unsigned __int64 Divisor = 1ULL << Shift; // Shift > 63 = Überlauf
		unsigned __int64 Precision = 1000000000;
		unsigned __int64 Float = (Fraction + Divisor) * Precision / Divisor; // Überlauf möglich
		float Check = Fraction / (float)Divisor;

		return 0;
	}
}
Mein Probleme scheinen nur die "Überläufe" zu sein. Gäbe es einen __int128 oder für double einen __int256, hätte ich vermutlich kein Problem.
Wie ich aus einer Ganzzahl/int einen string erzeuge, stellt kein Problem dar. Mein Problem liegt nur bei hohen Exponenten.

Ich habe ein wenig sprintf_s debuggt, und dort scheint man auch, nachdem man erstmal den "Template-Terror" hinter sich hat, eine besonders große Ganzzahl (big_integer) zu nutzen. Vielleicht sollte ich eine Klasse für besonders große Ganzzahlen programmieren und damit meine Probleme lösen?

Benutzeravatar
Krishty
Establishment
Beiträge: 6794
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [c++] [selfmade] float zu string konvertieren

Beitrag von Krishty » 19.11.2017, 15:32

Alle Plattformen und Programmiersprachen nutzen David Gays dtoa.c, zu dem es auch irgendwo ein Paper gibt. AFAIK, ja, nutzt das Big Integer Math. In dem Quelltext gibt es einen Kommentar /* Can we do an exact computation with 64-bit integer arithmetic? */, wahrscheinlich ist alles danach für dich von Interesse.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne

Benutzeravatar
Goderion
Beiträge: 82
Registriert: 16.09.2012, 12:02

Re: [c++] [selfmade] float zu string konvertieren

Beitrag von Goderion » 24.11.2017, 15:07

Vielen Dank für die Info.

dtoa.c von David M. Gay finde ich sehr anstrengend zu Lesen/Verstehen. Unzählige Präprozessor-Anweisungen und Variablen-Namen, wie von einem Mathematiker. ^^

Ich habe mir jetzt selber eine Klasse zum Rechnen mit großen Ganzzahlen programmiert und konvertiere damit Fließkommazahlen (float, double) in einen String. Die eigene Konvertierung ist zwar ziemlich langsam (ca. 10 mal so langsam wie sptrinf), aber da ich die Umwandlung momentan nur für Benutzereingaben benötige, ist das vorerst egal. Eine Optimierung zugunsten der Geschwindigkeit kann ich ja später noch machen. Wichtiger ist für mich, dass ich die Funktion verstehe und sie korrekt arbeitet.

Hier meine (unoptimierte/einfache) Klasse zum Rechnen mit großen (positiven) Ganzzahlen:
TemplateUIntX.h
(8.92 KiB) 129-mal heruntergeladen
Hinweise, Infos, Bug-Funde und Kritik sind immer willkommen.

Antworten