C# String in Double konvertieren - Problem

onfreak

Cadet 2nd Year
Registriert
Nov. 2007
Beiträge
21
Hallo!

Ich bin am verzweifeln...
Ich versuche einen string "140,7" in double zu parsen...

Ich entwickle eine Windows Azure Cloub-Applikation in C#.

Das Poblem:
Wenn ich den String in einer WebRole/WebForm parse funktioniert das einwandfrei!!!
Ich muss das aber in der WorkerRole machen und dann in eine Storage-Tabelle schreiben... Dort aber bekomme ich den wert 140,700000000001. Das geht natürlich nicht und im endeffekt steht dann 1407 in der Tabelle...

also mit CultureInfos habe ich schon alles probiert, auch mit verschiedenen Methoden... bekomme einfach nicht das richtige...

habt ihr einen tipp?
 
Code:
            System.Globalization.CultureInfo ci;
            ci = System.Globalization.CultureInfo.CreateSpecificCulture("de-DE");

            String s = "140,7";
            double d;

            d = Double.Parse(s, ci);
 
Hast du schon versucht, zuerst mit string.Replace , in . umzuwandeln?
 
Kann der Converter überhaupt ein Komma lesen? Dachte immer man muß einen Punkt benutzen damit die Konvertierung durch geht.
 
kommt auf die verwendete Culture an, bzw. was im System konfiguriert ist...

/edit: Ganz im Ernst, benutz decimal anstatt double dann wirst du dieses Problem nicht haben...
 
Zuletzt bearbeitet:
@haze4real: Was soll das bringen? oO
Decimal löst das Kulturproblem nicht.

Decimal löst lediglich das Genauigkeitsproblem, nicht aber das Konvertierungsproblem. Ob die Genauigkeit ein Problem darstellt, steht auf einem anderen Blatt.

Dieser Code zeigt, dass sich Decimal und Double bei der Umwandlung gleich verhalten:
Code:
    class Program
    {
        static double CastDouble(string s, string cc)
        {
            System.Globalization.CultureInfo ci;
            ci = System.Globalization.CultureInfo.CreateSpecificCulture(cc);

            return Double.Parse(s, ci);
        }

        static decimal CastDecimal(string s, string cc)
        {
            System.Globalization.CultureInfo ci;
            ci = System.Globalization.CultureInfo.CreateSpecificCulture(cc);

            return Decimal.Parse(s, ci);
        }

        static void Main(string[] args)
        {
            Console.WriteLine("DOUBLE");
            Console.WriteLine("140.7 ohne cc " + Double.Parse("140.7"));
            Console.WriteLine("140,7 ohne cc " + Double.Parse("140,7"));
            Console.WriteLine("140.7 mit US " + CastDouble("140.7", "en-US"));
            Console.WriteLine("140,7 mit US " + CastDouble("140,7", "en-US"));
            Console.WriteLine("140.7 mit DE " + CastDouble("140.7", "de-DE"));
            Console.WriteLine("140,7 mit DE " + CastDouble("140,7", "de-DE"));

            Console.WriteLine();

            Console.WriteLine("DECIMAL");
            Console.WriteLine("140.7 ohne cc " + Decimal.Parse("140.7"));
            Console.WriteLine("140,7 ohne cc " + Decimal.Parse("140,7"));
            Console.WriteLine("140.7 mit US " + CastDecimal("140.7", "en-US"));
            Console.WriteLine("140,7 mit US " + CastDecimal("140,7", "en-US"));
            Console.WriteLine("140.7 mit DE " + CastDecimal("140.7", "de-DE"));
            Console.WriteLine("140,7 mit DE " + CastDecimal("140,7", "de-DE"));


            Console.Read();
        }
    }

@feuse8: Möglich, aber nicht schön...
 
Zuletzt bearbeitet:
Moment, die Konvertierung passt doch ansich, bloß die Genauigkeit macht da nich mit. Verwendest du eine SQL Datenbank für deine "Storage-Tabelle"?
 
"Das geht natürlich nicht und im endeffekt steht dann 1407 in der Tabelle..." <-- das zeigt doch, dass es sich nicht um ein Genauigkeitsproblem sondern um eine Konvertierungsproblem handelt... das Komma in der Zahl wird einfach ignoriert weil es in manchen Kulturen lediglich zum Gruppieren von Ziffern verwendet wird... wie der Punkt im Deutschen (1.234.321,32 Euro).
 
schon richtig aber "Dort aber bekomme ich den wert 140,700000000001" ist meiner Meinung nach an Anzeichen der auf das Genauigkeitsproblem hindeutet. Was für einen Datentyp verwendest du in der Storage-Tabelle?
 
Richtig. Aber erklär mir mal, wie man von 140,700000000001 auf 1407 kommt. Die Ungenauigkeit stellt offensichtlich sogar kein Problem dar, schließlich spuckt der Code am Ende nicht den Wert 140700000000001 aus.

Die 1407 sind falsch. Und die sind kein Ergebnis von Ungenauigkeiten, sondern von falschen Kulturinformationen. Mit 140,700000000001 könnte man vermutlich sogar noch leben...

Beim Decimal passiert beim Parsen genau das selbe wie beim Double wenn die Kulturinformationen flasch sind - das Komma wird ignoriert et voilà haben wir unsere 1407.
 
Zuletzt bearbeitet:
erstmals danke für die schnellen antworten!

ich verwende keine sql-datenbank sondern Azure-TableStorage.

Deshalb kann ich auch kein decimal verwenden...

nur komisch ist, dass es in einer WebForm funktioniert, nur in der Worker role nicht?!??

also alle möglichen kulturoptionen waren vergebens... :(
 
Hast du den Code aus #2 ausprobiert?

Weil Beschreibungen "alles versucht" und "alle möglichen" usw helfen ehrlich gesagt gar nichts, weil ich kenne deine Definition von "alles" nicht und ich und die anderen nicht wissen können, was du genau gemacht hast. Wenn du selbst überzeugt wärst, wirklich alles mögliche versucht zu haben, würdest du ja wohl kaum noch auf eine Lösung hoffen ;-)
 
Was ist der Unterschied, was machst du bei der WebForm was du bei der Worker Role nicht machst? über den Azure Storage gehen? wenn ja, ist der Hund erstmal dort zu suchen. Welchen Datentyp benutzt du im Azure Storage, auch double? ein bisschen Code (Sample) wäre evtl hilfreich um dir zu helfen...
 
ja habe die möglichkeiten von #2 und #7 durchgespielt... ohne erfolg...

Macht es einen Unterschied ob man double oder Double nimmt?
Ergänzung ()

also beispielcode ist folgender:
while (true)
{
CloudQueueMessage messageNewEntry = queueWorkerInsert.GetMessage();
CloudQueueMessage messageUploadEntry = queueWorkerUpload.GetMessage();

// prüfen ob die Message Queue noch Daten zum eintragen enthält
if (messageNewEntry != null)
{
string messageContent = messageNewEntry.AsString;

string[] entries = messageContent.Split('#');

string distanz = entries[4];
distanz = distanz.Replace(".", ",");

double d1 = Helpers.CastDouble(distanz, "en-US");
double d2 = Helpers.CastDouble(distanz, "de-DE");

distanz = distanz.Replace(",", ".");

double d3 = Helpers.CastDouble(distanz, "en-US");
double d4 = Helpers.CastDouble(distanz, "de-DE");

string test = "140,7";
double dx = Convert.ToDouble(test);

//double test2 = Convert.ToDouble(distanz, System.Globalization.CultureInfo.InvariantCulture);

try
{
source.AddTagebuchEntry(new TagebuchEntity()
{
User = "1",
Sportart = entries[0],
Datum = Convert.ToDateTime(entries[1]),
Start = entries[2],
Dauer = entries[3],
Distanz = Convert.ToDouble(entries[4]),
Geschw = Convert.ToDouble(entries[5]),
Trainingsbereich = entries[6]
});

Trace.WriteLine("Entry creation successful");
CloudQueueMessage sendmessage = new CloudQueueMessage("true");
queueWeb.AddMessage(sendmessage);
queueWorkerInsert.DeleteMessage(messageNewEntry);
}
catch (Exception e)
{
Trace.WriteLine(e.Message);
CloudQueueMessage sendmessage = new CloudQueueMessage("false");
queueWeb.AddMessage(sendmessage);
queueWorkerInsert.DeleteMessage(messageNewEntry);
}

}

->mach ne Arbeit für eine Hochschule und hab als Beispiel ein Sport-Tagebuch...

von der webrole werden alle nötigen felder in einer queue zur worker role geschickt, die sich um den rest kümmert...

im oberen teil hab ich halt einen wert "distanz" als beispiel herausgenommen

unterer teil - addtagebuchentry - ist unverändert

achja, und ja der wert ist auch in der tabelle double
 
Zuletzt bearbeitet:
achso...
das ist fürs debuggen... ich hab geschaut was ich da für werte bekomme...

also die CastDouble methode ist die von #7

und als erstes schicke ich 140,7 rein.
da bekomme ich einmal 1407.0 und einmal 140,70000000001

und als zweites 140.7 (mit replace());
dasselbe...
Ergänzung ()

jetzt hab ich auch schon versucht das ergebnis 1407.0 durch 10 zu dividieren... dann bekomm ich wieder 140,70000000001 - ich verzweifle bald...
 
XD 1407 ist das Problem was 1668mib beschrieben hat mit der Culture bei welcher das Komma ignoriert wird, das andere mit dem 140,70000000001 ist das Genauigkeitsproblem von double und float. Wirste so nich um decimal herumkommen, jag mal folgende Zeile durchn Debugger und schau welchen Wert die Variable hat:

double omg = 1.5D - 1.1D;
 
Richtig, wenn dich bei 140,70000000001 die Ungenauigkeit stört, musst du auf decimal umstellen...
 
so ich habs jetzt gleich lassen :-)
bin auf integer umgestiegen, ich lass das mit dem komma... :cool_alt:

danke an alle!
 
Zurück
Oben