Autor Beitrag
digiveit
Hält's aus hier
Beiträge: 10

Windows XP Professional
Delphi 6 Enterprise
BeitragVerfasst: Mi 22.10.08 10:39 
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:

ausblenden 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;  // Eingabe: 1,369
  e1 := StrToFloat(s1);   // e1 = 1,369
  sgl1 := e1;             // sgl1 = 1,368999958 <- WARUM IST DAS SO?!?!? 
  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 user profile iconmatze: Code- durch Delphi-Tags ersetzt
hazard999
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 162

Win XP SP2
VS 2010 Ultimate, CC.Net, Unity, Pex, Moles, DevExpress eXpress App
BeitragVerfasst: 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.

_________________
MOV EAX, Result;MOV BYTE PTR [EAX], $B9;MOV ECX, M.Data;MOV DWORD PTR [EAX+$1], ECX;MOV BYTE PTR [EAX+$5], $5A;MOV BYTE PTR [EAX+$6], $51;MOV BYTE PTR [EAX+$7], $52;MOV BYTE PTR [EAX+$8], $B9;MOV ECX, M.Code;MOV DWORD PTR [EAX+$9], ECX
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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?

_________________
We are, we were and will not be.
hazard999
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 162

Win XP SP2
VS 2010 Ultimate, CC.Net, Unity, Pex, Moles, DevExpress eXpress App
BeitragVerfasst: Mi 22.10.08 10:49 
Einmal konvertieren ist besser:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var s1: string;
    sing: single;
begin
   s1 := Edit1.Text;
   sing := StrToFloatDef(s1, 0);
end;

_________________
MOV EAX, Result;MOV BYTE PTR [EAX], $B9;MOV ECX, M.Data;MOV DWORD PTR [EAX+$1], ECX;MOV BYTE PTR [EAX+$5], $5A;MOV BYTE PTR [EAX+$6], $51;MOV BYTE PTR [EAX+$7], $52;MOV BYTE PTR [EAX+$8], $B9;MOV ECX, M.Code;MOV DWORD PTR [EAX+$9], ECX
Timosch
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 1314

Debian Squeeze, Win 7 Prof.
D7 Pers
BeitragVerfasst: Mi 22.10.08 11:11 
Warum überhaupt Single? Warum nicht Extended?

_________________
If liberty means anything at all, it means the right to tell people what they do not want to hear. - George Orwell
digiveit Threadstarter
Hält's aus hier
Beiträge: 10

Windows XP Professional
Delphi 6 Enterprise
BeitragVerfasst: Mi 22.10.08 11:34 
user profile iconTimosch hat folgendes geschrieben Zum zitierten Posting springen:
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:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 4106
Erhaltene Danke: 13


Delphi 2010 Pro; Delphi.Prism 2011 pro
BeitragVerfasst: Mi 22.10.08 12:24 
Dann runde den Wert auf die gewüsnchte Anzhal von Stellen

_________________
Markus Kinzler.
digiveit Threadstarter
Hält's aus hier
Beiträge: 10

Windows XP Professional
Delphi 6 Enterprise
BeitragVerfasst: Mi 22.10.08 15:43 
user profile iconmkinzler hat folgendes geschrieben Zum zitierten Posting springen:
Dann runde den Wert auf die gewüsnchte Anzhal von Stellen

Hab ich auch schon probiert.
Geht aber nicht
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: Mi 22.10.08 15:46 
bei drei Nachkommastellen nimm doch currency!
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: 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.

_________________
Na denn, dann. Bis dann, denn.
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 23.10.08 14:18 
user profile iconBoldar hat folgendes geschrieben Zum zitierten Posting springen:
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.

_________________
Na denn, dann. Bis dann, denn.
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: Do 23.10.08 14:36 
currency-->nach string
string---> nach single
konvertieren, dann treten keine Rundungsfehler auf.
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 23.10.08 14:44 
user profile iconBoldar hat folgendes geschrieben Zum zitierten Posting springen:
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.
ausblenden 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?

_________________
Na denn, dann. Bis dann, denn.
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: Do 23.10.08 18:10 
ok, garnicht...
Du hast recht.
Denkfehler^^