Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - String to Single
digiveit - Mi 22.10.08 10:39
Titel: String to Single
Hallo zusammen,
ich gebe eine Kommazahl in ein Edit-Feld ein. Diese soll dann in eine Variable vom Typ Single umgewandelt werden und mit libnodave an eine S7 geschickt werden.
Jetzt habe ich das Problem, dass nach der Zuweisung an die Single-Variable mir Nachkommastellen erzeugt werden, die ich nicht haben möchte.
Hat jemand eine Ahnung warum das so ist?
Hier mein Quellcode:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| var s1: WideString; e1: Double; sgl1: Single;
begin
s1 := edtGewicht.Text; e1 := StrToFloat(s1); sgl1 := e1; NoDave.WriteFloat(12, e1); end; |
Hab es auch schon mit RoundTo usw. probiert, aber ohne Erfolg.
Was mache ich da falsch?
Vielen Dank schon mal für Eure Hilfe!
MfG
Veit
Moderiert von
matze: Code- durch Delphi-Tags ersetzt
hazard999 - Mi 22.10.08 10:47
Auszug aus WP:
[zitat]
Schon einfache Dezimalzahlen, z. B. 0,1, können nicht mehr exakt als binäre Gleitkommazahlen dargestellt werden, da viele im Dezimalsystem abbrechende Kommazahlen im Binärsystem nicht abbrechende, periodische Zahlen sind; von diesen werden nur die ersten p Ziffern gespeichert, wodurch Ungenauigkeit entsteht. Dezimal 0,1 ist binär 0,0001100110011… In einem binären Gleitkommasystem ist also 10 · 0,1 < 1, da die 0,1 abgerundet wird und nicht den exakten Wert approximiert.
[/zitat]
Das passiert wenn du einen Datentyp grösserer Genauigkeit in einen mit kleiner Genauigkeit umwandelst.
Gausi - Mi 22.10.08 10:49
Das liegt an der internen Darstellung der Zahl im Binärsystem. Der Wert 1,369 kann im Dualsystem nicht genau dargestellt werden (oder nur mit sehr viel mehr Stellen), so dass es dann zu Ungenauigkeiten kommt.
Wirklich beheben kann man das nicht, evtl. ist der Datentyp Currency was für dich. Oder klappt vielleicht die direkte Zuweisung MySingleVar := StrToFloat(sMyString); besser?
hazard999 - Mi 22.10.08 10:49
Einmal konvertieren ist besser:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| var s1: string; sing: single; begin s1 := Edit1.Text; sing := StrToFloatDef(s1, 0); end; |
Timosch - Mi 22.10.08 11:11
Warum überhaupt Single? Warum nicht Extended?
digiveit - Mi 22.10.08 11:34
Timosch hat folgendes geschrieben : |
| Warum überhaupt Single? Warum nicht Extended? |
Weil ich mit libnodave die Daten an eine SPS S7-Steuerung schicken möchte und dort der Übergabeparameter ein Single ist:
Delphi-Quelltext
1:
| NoDave.WriteFloat(12, sgl1); |
Ich möchte halt in der SPS genau 1,369 drin stehen haben und nicht 1,368999958.
Muss doch irgendwie machbar sein, oder nicht?!?
MfG
Veit
mkinzler - Mi 22.10.08 12:24
Dann runde den Wert auf die gewüsnchte Anzhal von Stellen
digiveit - Mi 22.10.08 15:43
mkinzler hat folgendes geschrieben : |
| Dann runde den Wert auf die gewüsnchte Anzhal von Stellen |
Hab ich auch schon probiert.
Geht aber nicht
Delphi-Quelltext
1:
| sgl2 := RoundTo(sgl1, -3); |
liefert mir in sgl2 wieder den Wert mit den vielen Kommastellen.
Noch andere Vorschläge?
MfG
Veit
Boldar - Mi 22.10.08 15:46
bei drei Nachkommastellen nimm doch currency!
alzaimar - Mi 22.10.08 16:27
Lass man, eigentlich ist das das Gleiche (1,369 vs. 1,368999958), Du bemängelst einen Fehler von 0,000003%, das ist lächerlich. Es ist nunmal so, wie oben schon erwähnt, das sich die Zahl 1,369 *NICHT* exakt in einem Single-Datentyp darstellen lässt. Punkt.
Grundsätzlich: Bei Floating Point-Datentypen muss man die letzten 2-3 Stellen ignorieren.
Bei Deinem Problem würde ich (nun nicht gerade bei dem einfachen Beispiel) mit Double oder Extended rechnen und dann den Wert vor der Übergabe in einen Single umrechnen. Mit Single würde ich nur sehr einfache Rechnungen durchführen.
Wenn Du z.B. einen Stab der Länge 100cm hast, ist der garantierte nie genau 100cm lang. In diesem Fall wäre er 100,000003 cm lang. Na nun.
Boldar - Do 23.10.08 14:10
Aber wenn man currency nimmt, treten KEINE Rundungsfehler auf!!
Weil Currency-Daten nicht als Gleitkommazahlen gespeichert werden, sondern als integer.
alzaimar - Do 23.10.08 14:18
Boldar hat folgendes geschrieben : |
| Aber wenn man currency nimmt, treten KEINE Rundungsfehler auf!! |
Und wenn man sie in Single konvertiert? :lol: Die tritt doch spätestens bei der Übergabe an die SPS auf.
Currency ist ein sehr schöner Datentyp, wenn man nur addiert bzw. subtrahiert, weil man sich dann nicht mit den Schutzstellen herum ärgern muss. Als allgemeiner Datentyp in wissentschaftlich-mathematischen Anwendungen eignet er sich jedoch aufgrund der beschränkten Genauigkeit nicht.
Boldar - Do 23.10.08 14:36
currency-->nach string
string---> nach single
konvertieren, dann treten keine Rundungsfehler auf.
alzaimar - Do 23.10.08 14:44
Boldar hat folgendes geschrieben : |
| konvertieren, dann treten keine Rundungsfehler auf. |
Doch, weil 1,369 kein Element der Menge der im Datentyp 'Single' darstellbaren Zahlen ist. Das wurde hier doch nun schon mehrfach erklärt.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| Procedure TForm1.ZeigsMir; Const Zahl = '1,369';
Var s: Single; d : Double; e : Extended;
begin s := StrToFloat(Zahl); d := StrToFloat(Zahl); e := StrToFloat(Zahl); memo1.Lines.Add(Format('Single : %8.15f',[s])); memo1.Lines.Add(Format('Double : %8.15f',[d])); memo1.Lines.Add(Format('Extended: %8.15f',[e])); end; |
Wie schaffst Du es, das in einem Single die Zahl '1,369' steht?
Boldar - Do 23.10.08 18:10
ok, garnicht...
Du hast recht.
Denkfehler^^
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!