![]() |
Gleitkommadivision...?
Hi,
ich habe zahlen in der art:
Code:
wenn ich die zahl durch 10 teile, sollte die meines erachtens so aussehen:
16502,62
Code:
wenn ich die allerdings mit dem gleitkomma / teile, kommt das raus:
1650,262
Code:
:shock:
0,002...
div kann man da ja nicht verwenden! was ist denn da los? *MFG* |
Re: Gleitkommadivision...?
Zeig mal deinen Code, das kann ich mir nämlich nicht so recht vorstellen...
|
Re: Gleitkommadivision...?
Vielleicht isses ja noch so nen dummer delphi-bug, wie dieser:
Wenn man
Code:
das hier sich mal anschaut ... müsste doch logischerweise 0 dabei rauskommen, oder? delphi lässt aber -6,7762635780344E-20 rauskommen ... :roll: ... komischerweise ... :gruebel:
var
r : real; r := 1 - 0.1 - 0.1 - 0.1 - 0.1 - 0.1 - 0.1 - 0.1 - 0.1 - 0.1 - 0.1; ShowMessage(FloatToStr(r)); ciao, Philipp |
Re: Gleitkommadivision...?
ok hier ein bisschen code:
Delphi-Quellcode:
function GetPrinterRes(const pobj: TPrinter; Horz: Boolean): integer;
var Index: Integer; begin if Horz then Index:=LOGPIXELSX else Index:=LOGPIXELSY; Result:=GetDeviceCaps(pobj.Handle, Index); end; function ConvertPixelstoMMX(const Value:Integer):Double; begin Result := Value / GetPrinterRes(Printer, True) * mmPerInch; end; ... hlplabel.Caption := hlplst.Strings[x]; length := length + roundto(ConvertPixelsToMMX(hlplabel.Width), -2); length := length / 10; pllength.Caption := floattostr(length) + ' m'; |
Re: Gleitkommadivision...?
hast du mal durch 10.0 geteilt?
|
Re: Gleitkommadivision...?
Zitat:
@Meflin: Geh mal im Einzelschrittmodus durch und überprüf den Wert von Length, da muss der Knackpunkt liegen, nicht an der Division durch 10! |
Re: Gleitkommadivision...?
das habe ich schon getan, der wert "spinnt" erst nach der teilung!
|
Re: Gleitkommadivision...?
Das Problem liegt in der Natur der Fließkommazahlen... Nimm einfach mal als Beispiel den Datentyp Double. Der hat intern eine Speicherstruktur von 8 byte. Mit diesen 8 byte, entsprechend 64 bit, kannst du also maximal 2^64=1,8447*10^19 verschiedene Werte speichern. In der Mathematik lernst du aber natürlich, daß es unendlich viele Elemente aus R gibt... Somit steht also auch klar, daß du im Rechner NIE alle reellen Zahlen darstellen kannst, sondern immer nur mit einer gewissen Genauigkeit... Und diese Ungenauigkeit die du in deinem Rechenbeispiel kriegst, liegt hierdrin begründet.
Gruß |
Re: Gleitkommadivision...?
hm versteh ich nicht wirklich :stupid: die zahl ist ja nicht besonders groß :gruebel: aber die ungenauigkeit dafür riesig. wie könnte cih dann das problem umgehen?
|
Re: Gleitkommadivision...?
Zitat:
Oder waren die Werte aus dem ersten Post falsch? Grundsäzlich gilt auf jeden Fall (da es Fließkomma- und nicht Festkommazahlen sind: je kleiner der Betrag der Zahl, desto kleiner die Abstände zwischen den darstellbaren Zahlen. |
Re: Gleitkommadivision...?
das gibts doch nicht :? die teilung durch 10.0 löst das ganze btw auch nicht!
|
Re: Gleitkommadivision...?
Die 10 wird vom Compiler ohnehin in 10.0 ungewandelt.
|
Re: Gleitkommadivision...?
das kanns doch garnicht geben... es ist fast der ganze source des programms, der restliche hat mit den dort verwendeten variablen nichts zutun. weis keiner mehr weiter? :cry:
|
Re: Gleitkommadivision...?
Zitat:
BeginDoc geöffnet hast. Die Umrechnung von Pixels -> mm benötigt immer eine Auflösung. Willst du mit der Druckerauflösung oder mit der Bildschirmauflösung (72 oder 96 DPI) arbeiten ? Wenn ich einen Wert in mm (Millimeter) durch 10.0 teile, dann bin ich bei cm (Zentimeter). Bei dir steht aber m (Meter); warum ??? Der Datentyp der Variablen length muss Double oder Extended sein! Du solltest die Variable umbenennen, damit es nicht zu einem Namenskonflikt mit der RTL-Funktion Length() kommt! |
Re: Gleitkommadivision...?
Code:
:wall:
ThisPost.location := nil;
|
Re: Gleitkommadivision...?
Zitat:
Zitat:
Zitat:
Zitat:
|
Re: Gleitkommadivision...?
length ist umbenannt, hat nix gebracht
|
Re: Gleitkommadivision...?
^^ push ^^
|
Re: Gleitkommadivision...?
:?
|
Re: Gleitkommadivision...?
:( nochmal push...
|
Re: Gleitkommadivision...?
Test mit Delphi 7 Ent. mit folgendem Code:
Delphi-Quellcode:
Ich habe für a, b und c alle Gleitkommatypen durch (incl. Currency), und ich hatte nur bei Single eine kleine Abweichung weit im Nachkommaanteil.
procedure TForm1.Button1Click(Sender: TObject);
var a, b, c: Extended; begin a := StrToFloat(Edit1.Text); b := StrToFloat(Edit2.Text); c := a/b; Edit3.Text := FloatToStr(c); end; Daher ist das Verhalten für mich nicht reproduzierbar - sorry :spin:. gruss, Fabian |
Re: Gleitkommadivision...?
Liste der Anhänge anzeigen (Anzahl: 1)
um das thema nochmals aufzugreifen, habe ein gleihgeartetes problem
siehe anhang! db: ib hat damit aber glaube ich nix zu tun eher mit strtofloat konvertierung z.b. wird bei float feldern manchmal aus 0,2 = 0,20000000002980232 oder aus 0,1=0,100000000014910116 woher kann dieses 14910116 kommen vom code her jedenfalls nicht, da bin ich mir ganz sicher und wenn man sich das genauer ansieht, dann ist 2*14910116=2980232 usw. hat jemand auch schon mal diese phänomen gehabt? |
Re: Gleitkommadivision...?
Ich hatte mal ein ähnliches Problem und konnte es lösen indem ich einen anderen Float-Datentyp gewählt habe. (Damals Currency, dann war 0.2 auch 0.2....)
Ich vermute, dass das daran lag, dass ich mit verschiedenen Datentypen gerechnet habe. (z.B. Extended= Double / Real) Es sollten wirklich alle Variablen möglichst gleichen Typs sein und wenn nicht, dann am besten in Einzelschritten umwandeln. Ich weiß nicht ob euch das was bringt, aber bei mir ging das dann... PS: achso.. am besten niemals Real verwenden... das gibts soweit ich weiß nur aus Kompatiblitätsgründen... Edit: @idp Wie weist du deinen Datensätzen die Werte zu? ich hatte schonmal genau das selbe Problem... War allerdings eine Access-Datenbank. Poste am besten mal nen Source, oder werden die Tabellen über eine DataGrid-Komponente gefüllt? |
Re: Gleitkommadivision...?
sie werden nicht über ein grid erstellt, sondern per query
Delphi-Quellcode:
function TInkaRecord.UpdRec(aPKey:TInkaKey):boolean;
var i:integer; s:string; inkaField:TInkaRecField; allowtyp:TinkaFieldSet; begin allowTyp:=[inkaFtPKey, inkaFtRef, inkaFtText, inkaFtInt, inkaFtFloat, inkaFtMemo, inkaFtBool, inkaFtDate, inkaFtStart, inkaFtViewer]; // insert Record query.SQL.Clear; query.sql.add('update '+tableRef.tname); // set fieldname s:='set '+tableRef.prefix+'_parkey=:parkey'; for i:=0 to fieldCount-1 do begin if not (TInkaRecField(fieldList.Objects[i]).typ in allowTyp) then continue; s:=s+','+fieldList.Strings[i]+'=:'+fieldList.Strings[i]; end; query.sql.add(s); query.sql.add('where '+tableRef.prefix+'_pkey=:pkey'); query.ParamByName('parkey').asString:=recParKey; query.ParamByName('pkey').asString:=aPKey; // parametrisieren for i:=0 to fieldCount-1 do begin if not (TInkaRecField(fieldList.Objects[i]).typ in allowTyp) then continue; inkaField:=TInkaRecField(fieldList.Objects[i]); inkaField.setToQuery(query,fieldList.Strings[i]); end; result:=true; try query.ExecSQL; except on e:Exception do begin showmessage('Fehler beim aktualisieren des Datensatzes!'+#13 +query.SQL.Text+#13 +e.Message); result:=false; end; // on end; // try..except end; |
Re: Gleitkommadivision...?
Sehr viel weiter hilft der QT auch nicht.. Aber zumindest verwendest du Parameter (komischerweise tun das viele nicht).
Von welchem Typ ist "query"? TIbQuery, TAdoQuery? Sind
Delphi-Quellcode:
selbst definiert oder wo kommen die her?
inkaField:TInkaRecField;
allowtyp:TinkaFieldSet; Die Problem liegt bestimmt beim parametrisieren aber das scheint "inkaField" zu machen. Sind die Abweichungen wenn du den Datentyp des Parameters zu Testzwecken zwischen ftFloat, ftCurrency und ftBCD variierst gleich? Bzw welche Datentypen stehen in dem inkaField und.. Sind die Werte dort auch schon ungenau? PS: Warum benötigt Oracle-Installation eigentlich so extrem viel Zeit? |
Re: Gleitkommadivision...?
Diese minimalen Abweichungen sind vollkommen normal, und haben nichts mit einem Bug zu tun. Das Thema hatten wir hier auch schon des öfteren :roll: ;).
Ursache: Die Art und Weise nach der ein Float-Typ gebildet wird - und zwar nicht nur in Delphi, sondern überall. Um das evtl. mal abschließend zu klären hier mal der Aufbau einer 32-Bit Gleitkommazahl (also einfache Genauigkeit = "Single")
Code:
Ich hoffe es war die Mühe wert, und es wurde klar warum Float-Typen immer nur begrenzt akkurat sein können.
Binärer Aufschrieb: 32 Bits
00000000000000000000000000000000 |\_____/\______________________/ | | mantisse | exponent | Vorzeichenbit Die dezimale Darstellung errechnet sich nach folgender Formel: x = (-1)^Vorzeichenbit * 2^(exponent - T) * 1.mantisse wobei T = 127 (bei Single; bei Double ist T = 1023) angenommen wir wollen die Zahl 0.2 so darstellen, so ergäbe sich: Vorzeichenbit = 0 exponent = 124 { 2^(124 - 127) = 2^(-3) = 0.125 } mantisse = 0.6 { und das wird unser Problemkind } Warum ist die Matisse das Problem? Weil sie [b]binär[/b] dargestellt werden muss! Und das ist: 0.6(d) = 0.1001100110011001100110011001100110011001100110011001100110011.....(b) => Also [b]periodisch[/b]! Aber die Matisse bietet uns keinen Platz für eine Periode, also wird irgendwo abgeschnitten: nämlich nach 24 Bits. Also gilt binär: Vorzeichenbit = 0 exponent = 1111100 mantisse = 100110011001100110011001 Gesamte Zahl binär: 01111100100110011001100110011001 (In Hex: 7C999999) Jetzt wollen wir mal zurück rechnen: Vorzeichenbit ist = 0, also positives Vorzeichen. Den Exponenten haben wir oben schon mal, 2^(-3) = 0.125 Jetzt die Mantisse. Nach dem Komma rechnent sich die binäre Zahl folgendermaßen um: erstes Bit*(2^(-1)) plus zweites Bit*(2^(-2)) plus drittes Bit*(2^(-3)) usw. (von [b]links[/b] angefangen, nicht wie bei ganzen Zahlen von rechts!) Für unsere Mantisse ergibt sich daher: [size=9](Jetzt wirds unschön *g*)[/size] 2^(-1)+2^(-4)+2^(-5)+2^(-8)+2^(-9)+2^(-12)+2^(-13)+2^(-16)+2^(-17)+2^(-20)+2^(-21)+2^(-24) Die Summanden ausgerechnet: 0.5 + 0.0625 + 0.03125 + 0.00390625 + 0.001953125 und ab hier verlässt mich der Taschenrechner mit seiner Anzeige, daher sei nur gesagt, dass noch einige weiter winzige Werte aufaddiert werden, bis zu einem Endergebnis von: ca. 0.5999999[b]64[/b] Und das fett gedruckte ist nun der Fehler der beim Rechnen mit Floatzahlen nunmal prinzipbedingt auftreten kann. Ob, und wie stark dieser ist hängt davon ab, wie gut sich die nötige Mantisse binär umgerechnet in die dafür vorgesehenen Bits passen. Um unsere 0.2 zu ende zu rechnen: Wir haben jetzt alle nötigen Werte, und die Formel lautet: (allerdings nur ungefähr, da mein TR ja nur so wenige Stellen hat ;)) 2^(-3) * 1.599999964 = 0.125 * 1.599999964 = 0.19999995 (cirka) Und schwupps ist unsere 0.2 etwas kleiner geworden, und zwar ohne dass wir etwas dagegen tun könnten! Dass die 0.2 im obigen Beitrag größer, und nicht wie hier kleiner geworden ist, liegt wahrscheinlich daran, dass nicht Single als Datentyp benutzt wurde. Je nach Typ verändert sich die Darstellbarkeit der Werte drastisch! Allerdings erklärt dieser Umstand das ursprüngliche Problem hier nicht! Dafür ist der Fehler zu groß, und muss andere Ursachen haben. Gruss, Fabian \\edit: Korrektur: Der Exponent hat bei mir hier 7 binäre Stellen - er hat aber 8! Dafür hat die Mantisse nicht 24, sondern 23 Stellen... denkt's euch bidde zurecht :) |
Re: Gleitkommadivision...?
@RBredereck
Zitat:
Zitat:
Zitat:
Zitat:
@dizzy Zitat:
wie kann man das dann umgehen? mit welchen typ oder gibt es einen korrekturfaktor? |
Re: Gleitkommadivision...?
Zitat:
Also ist die Top-Genauigkeit (mit generischen Typen) Double bzw. Extended. Wenn du es 100%ig brauchst, dann böte sich evtl. eine Library an die die Daten anders hinterlegt (z.B. als String). (Kenne spontan keine für Floats.) Eine andere Sache ist: Wie genau brauchst du's denn? Reichen evtl. nicht so 10 Stellen nach dem Komma? Dann kann man mit Runden noch was reissen :D. btw: Mit der o.g. genormten Darstellung von Floats ist übrigends die Null unmöglich. Da wird dann aber in der FPU ein Flag geführt. |
Re: Gleitkommadivision...?
Zitat:
Das Problem ergab sich als ich folgende Einstellungen hatte: Datentyp in der Datenbank: Float Datentyp den ich der Datenbank zugewiesen habe: Currency Ich stellte das dann wie folgt um: Datentyp in der Datenbank: Money (Access) Datentyp in den ich geweise: Currency Ich kann es mir nur so erklären, dass die Datenbank einen Float mit großer Genauigkeit erwartet hat, meine Werte jedoch diese nicht besaßen und es deshalb zu den Problemen kam. Jetzt haben beide die selbe Genauigkeit und es funktioniert. Es kann natürlich auch eine ganz andere Ursache gewesen sein, die ich dadurch aber umgehen konnte. Evtl kannst Du auch über SQL die Werte nachträglich Runden (also gerundet(Wert*10^n)*10^-n - weiß jetzt aber nicht den genauen Befehl... geht aber auf jeden Fall... Du musst dann nur Wissen ob das vertretbar ist (meinetwegen ab der 6. Stelle zu Runden) und ob du mit einer solchen unsicheren Lösung leben kannst. Solltest du das Problem lösen (egal wie) poste es bitte.. also viel Glück noch... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:26 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz