FloatToStr liefert falschen Wert (nach IDirect3D.CreateDev*)

Rund um die LCL und andere Komponenten
Antworten
MitjaStachowiak
Lazarusforum e. V.
Beiträge: 386
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

FloatToStr liefert falschen Wert (nach IDirect3D.CreateDev*)

Beitrag von MitjaStachowiak »

Hallo,
ja, ich weiß, ich habe schon mal eine Frage zu FloatToStr gestellt. Aber dieses Mal habe ich ein anderes Problem:

Code: Alles auswählen

unit Unit1; 
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, Forms, Windows, Controls, Dialogs, direct3d9;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.FormCreate(Sender: TObject);
var
 d3ddm   : TD3DDisplayMode;
 D3DDev9 : IDirect3DDevice9;
 D3D9    : IDirect3D9;
 d3dpp   : TD3DPresent_Parameters;
begin
 
 // Create DirectX
 D3D9 := Direct3DCreate9(D3D_SDK_VERSION);
 Fillchar(d3dpp, sizeof(d3dpp), 0);
 with (d3dpp) do begin
  SwapEffect := D3DSWAPEFFECT_DISCARD;
  Windowed := true;
  D3D9.GetAdapterDisplayMode(D3DADAPTER_DEFAULT,d3ddm);
  BackBufferFormat := d3ddm.Format;
 end;
 D3D9.CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,Handle,D3DCREATE_SOFTWARE_VERTEXPROCESSING,@d3dpp,D3DDev9);
 
 Showmessage(FloatToStr(0.10000000149012))// Shows 0,2 ???
 
end;
 
end.


In der Messagebox steht bei mir immer 0,2!!!

Mal abgesehen davon, dass der Code zum Erzeugen von DirectX total sinnlos ist (Ich habe es soweit wie möglich reduziert), ist die Problematik klar: 0.10000000149012 <> 0,2, auch wenn man rundet :|

Ich verwende die Header von http://clootie.ru/ Aber auch mit diesen hier (http://www.delphidev.de/forum/viewtopic.php?id=752) tritt der Fehler auf.
Irgendwo gibt es anscheinend ein Memory leak - bevor ich jetzt in DirectX danach suche, möchte ich darum bitten, dass Ihr mal in verschiedenen, größeren Programmen die fragliche Zeile einfügt, um zu sehen, ob sich der Fehler auf DirectX beschränkt.

Ich habe allgemein keine große Erfahrung mit solchen Fehlern - wo und wie muss ich als nächstes suchen?

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2548
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: FloatToStr liefert falschen Wert (nach IDirect3D.CreateD

Beitrag von m.fuchs »

Ich bin mir jetzt nicht sicher, aber eventuell hilft die mein Halbwissen über Direct3D bei der Suche nach dem Problem.

Soweit ich mich erinnere, ändert Direct3D standardmäßig die Fließkomambehandlung für den laufenden Thread (oder gar die ganze Applikation?). Was du da hast ist also nicht unbedingt ein Fehler, sondern eine Vereinfachung der Fließkomaarithmtik. Das Ganze passiert natürlich aus Performancegründen. Man kann wohl beim Erzeugen ds Direct3D-Kontext irgendwie den Modus für FPU-Benutzung ändern.

Das vielleicht mal als Ansatz für eine Google-Recherche.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

BeniBela
Beiträge: 298
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: FloatToStr liefert falschen Wert (nach IDirect3D.CreateD

Beitrag von BeniBela »

Keine Ahnung was mit DirectX ist, aber ich wollte mal anmerken, dass dieses FloatToStr sowieso ein katastrophaler Murks ist.
Am besten verwendet man es überhaupt nicht

Code: Alles auswählen

writeln(FloatToStr(100000000000000));


gibt 1 aus! 1!

(zumindest mit fpc 2.6 auf Linux)

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: FloatToStr liefert falschen Wert (nach IDirect3D.CreateD

Beitrag von Scotty »

Wenn du dir den Quellcode ansiehst, weisst du auch, warum das passiert.

Code: Alles auswählen

  Result := FloatToStrFIntl(e, ffGeneral, 15, 0, fvComp,FormatSettings);

Es ist eben nicht unbedingt sinnvoll, eine Zahl mit mehr als 15 Stellen als String auszugeben. (Genauso bedenklich ist es aber auch, keine Warnung anzuzeigen.)
Andererseits gibt es ja genug Alternativen.

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 386
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: FloatToStr liefert falschen Wert (nach IDirect3D.CreateD

Beitrag von MitjaStachowiak »

Ahaaa, DirectX verändert was an der Rechenaritmetik.?

Meine Google-Recherche war keider nicht sehr ergiebig, was zum Teil daran liegt, dass, sobald DirectX im Suchbegriff auftaucht, man mit Gamingforen überschüttet wird :x

Ich soll also einfach eine eigene FloatToStr-Funktion basteln und dem Projekt beilegen? Kennt jemand eine gute Vorlage?

PS:
Ich habe das mit dem Thread mal getestet (Meine Anwendung verwendet sowieso separate Threads): In den anderen Threads wird das korrekte Ergebnis angezeigt.
Wegen Performanceverbesserung:

Code: Alles auswählen

 
 s := 1;
 c := GetTickCount;
 for i := 0 to 1000000000 do s := (s + 1) / s;
 Showmessage(IntToStr(GetTickCount-c));
 
 D3D9.CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,Handle,D3DCREATE_SOFTWARE_VERTEXPROCESSING,d3dpp,D3DDev9);
 
 s := 1;
 c := GetTickCount;
 for i := 0 to 1000000000 do s := (s + 1) / s;
 Showmessage(IntToStr(GetTickCount-c));

Dieser Code zeigt bei mir 10530 und dann 7379 an. Außerdem wirft Division durch Null bei DX kein Exception. Scheint wirklich was zu bringen ;-)
Zuletzt geändert von MitjaStachowiak am Mi 7. Nov 2012, 11:09, insgesamt 1-mal geändert.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: FloatToStr liefert falschen Wert (nach IDirect3D.CreateD

Beitrag von mse »

MitjaStachowiak hat geschrieben:Ich soll also einfach eine eigene FloatToStr-Funktion basteln und dem Projekt beilegen? Kennt jemand eine gute Vorlage?

http://gitorious.org/mseide-msegui/mseide-msegui/blobs/master/lib/common/kernel/msefloattostr.pas

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 386
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: FloatToStr liefert falschen Wert (nach IDirect3D.CreateD

Beitrag von MitjaStachowiak »

Ja, jetzt geht's!

Ich habe die alternative Deklaration von FloatToStr bei mir einfach in der Unit Direct3D9 eingefügt; so passiert der Fehler in der Unit, die DX importiert, von ganz alleine nicht mehr, ohne dass man an irgendetwas denken muss. In verlinkten Units muss man aber nachhelfen.

Naja, Danke euch allen :-)

BeniBela
Beiträge: 298
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: FloatToStr liefert falschen Wert (nach IDirect3D.CreateD

Beitrag von BeniBela »

Scotty hat geschrieben:

Code: Alles auswählen

  Result := FloatToStrFIntl(e, ffGeneral, 15, 0, fvComp,FormatSettings);

Es ist eben nicht unbedingt sinnvoll, eine Zahl mit mehr als 15 Stellen als String auszugeben. (Genauso bedenklich ist es aber auch, keine Warnung anzuzeigen.)
Andererseits gibt es ja genug Alternativen.


Mehr als 15 Stellen ist kein Problem.

Dann schreibt es ja 1E16

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: FloatToStr liefert falschen Wert (nach IDirect3D.CreateD

Beitrag von Scotty »

BeniBela hat geschrieben:Mehr als 15 Stellen ist kein Problem. Dann schreibt es ja 1E16

Ich war eigentlich verblüfft, dass tatsächlich 1 rauskommt:

Code: Alles auswählen

Caption:=FloatToStrF(100000000000000, ffGeneral, 15, 0, FormatSettings);//=1
Caption:=FloatToStrF(100, ffGeneral, 3, 0, FormatSettings);//=1
 

Bei einer Stelle mehr oder weniger liefert die Funktion korrekt den Exponenten. Ist also ein Bug.
--
Lazarus 0.9.31 r35571 FPC 2.6.0 i386-win32-win32/win64

gocher
Beiträge: 298
Registriert: Di 23. Nov 2010, 23:41
OS, Lazarus, FPC: Ubuntu/Win, Lazarus trunk, FPC trunk
CPU-Target: 32Bit/64Bit
Wohnort: Geldern
Kontaktdaten:

Re: FloatToStr liefert falschen Wert (nach IDirect3D.CreateD

Beitrag von gocher »

Mit der SVN Version tritt der Fehler nicht mehr auf!
Lazarus version: 1.1
Lazarus svn revision: 39247M
Lazarus was compiled for i386-win32
Lazarus was compiled with fpc 2.7.1
Free Pascal svn revision: 22947

Der Fehler wurde behoben in:

Revision: 19738
Author: jonas
Date: Samstag, 3. Dezember 2011 23:34:00
Message:
* let FloatToStr output the correct number of decimals in case the
first significant digit is preceded by several zeroes (patch by
C. Western, mantis #16907)

----
Modified : /trunk/rtl/objpas/sysutils/sysstr.inc
Modified : /trunk/tests/test/units/sysutils/tfloattostr.pp
MfG Gocher
akt. Projekt: Webserver(HTTPS HTTP/2) mit integrierten CMS in Free Pascal - www.gocher.me

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: FloatToStr liefert falschen Wert (nach IDirect3D.CreateD

Beitrag von marcov »

Der rev ist merged nach 2.6.2

Antworten