AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Gleitkommadivision...?

Ein Thema von Meflin · begonnen am 15. Sep 2004 · letzter Beitrag vom 29. Sep 2004
Antwort Antwort
Seite 3 von 3     123   
Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#21

Re: Gleitkommadivision...?

  Alt 24. Sep 2004, 19:40
Test mit Delphi 7 Ent. mit folgendem Code:
Delphi-Quellcode:
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;
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.

Daher ist das Verhalten für mich nicht reproduzierbar - sorry .


gruss,
Fabian
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat
Benutzerbild von ibp
ibp

Registriert seit: 31. Mär 2004
Ort: Frankfurt am Main
1.511 Beiträge
 
Delphi 7 Architect
 
#22

Re: Gleitkommadivision...?

  Alt 29. Sep 2004, 14:16
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?
Miniaturansicht angehängter Grafiken
floatdb.png  
  Mit Zitat antworten Zitat
RBredereck
(Gast)

n/a Beiträge
 
#23

Re: Gleitkommadivision...?

  Alt 29. Sep 2004, 14:37
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?
  Mit Zitat antworten Zitat
Benutzerbild von ibp
ibp

Registriert seit: 31. Mär 2004
Ort: Frankfurt am Main
1.511 Beiträge
 
Delphi 7 Architect
 
#24

Re: Gleitkommadivision...?

  Alt 29. Sep 2004, 14:56
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;
  Mit Zitat antworten Zitat
RBredereck
(Gast)

n/a Beiträge
 
#25

Re: Gleitkommadivision...?

  Alt 29. Sep 2004, 15:30
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:
   inkaField:TInkaRecField;
   allowtyp:TinkaFieldSet;
selbst definiert oder wo kommen die her?

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?
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#26

Re: Gleitkommadivision...?

  Alt 29. Sep 2004, 16:06
Diese minimalen Abweichungen sind vollkommen normal, und haben nichts mit einem Bug zu tun. Das Thema hatten wir hier auch schon des öfteren .
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:
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!
Ich hoffe es war die Mühe wert, und es wurde klar warum Float-Typen immer nur begrenzt akkurat sein können.
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
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat
Benutzerbild von ibp
ibp

Registriert seit: 31. Mär 2004
Ort: Frankfurt am Main
1.511 Beiträge
 
Delphi 7 Architect
 
#27

Re: Gleitkommadivision...?

  Alt 29. Sep 2004, 17:14
@RBredereck

Zitat von RBredereck:
Sehr viel weiter hilft der QT auch nicht.. Aber zumindest verwendest du Parameter (komischerweise tun das viele nicht).


Zitat:
Von welchem Typ ist "query"? TIbQuery, TAdoQuery?
TQuery

Zitat:
Sind
Delphi-Quellcode:
   inkaField:TInkaRecField;
   allowtyp:TinkaFieldSet;
selbst definiert oder wo kommen die her?
ja

Zitat:
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?
nein nicht beim parametrisiren und inkafield ist eine klasse und hat nur tabelleninformationen, die werte sind nur in der db ungenau oder bei reports, da stören sie auch extrem!

@dizzy
Zitat:
Diese minimalen Abweichungen sind vollkommen normal, und haben nichts mit einem Bug zu tun. Das Thema hatten wir hier auch schon des öfteren .
Ursache: Die Art und Weise nach der ein Float-Typ gebildet wird - und zwar nicht nur in Delphi, sondern überall.
so etwas habe ich mir auch schon gedacht, aber minimal finde ich den fehler nicht gerade, es kommt doch immer darauf an für was die werte stehen!
wie kann man das dann umgehen? mit welchen typ oder gibt es einen korrekturfaktor?
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#28

Re: Gleitkommadivision...?

  Alt 29. Sep 2004, 18:56
Zitat von ibp:
wie kann man das dann umgehen? mit welchen typ oder gibt es einen korrekturfaktor?
Einen Korrekturfaktor kann es imho nicht geben, da nach der Umwandlung ja nicht mehr eindeutig ist welche Zahl ursprünglich hineingesteckt wurde. So würde (vermute ich mal) 0.2 und 0.20000001 zur selben Zahl bei Single-Typen führen, und du bekommst ja nie wieder heraus, welche Zahl nun wirklich genommen wurde. Das ganze ist ein konzeptionelles Problem, und lässt sich (faktisch) garnicht lösen. Der Fehler lässt sich lediglich minimieren: Durch mehr Bits
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 .


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.
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat
RBredereck
(Gast)

n/a Beiträge
 
#29

Re: Gleitkommadivision...?

  Alt 29. Sep 2004, 19:30
Zitat:
nein nicht beim parametrisiren und inkafield ist eine klasse und hat nur tabelleninformationen, die werte sind nur in der db ungenau oder bei reports, da stören sie auch extrem!
Nagut... bei mir war das so:

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...
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 3 von 3     123   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:16 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz