FloatBug in Proceduren

Fragen und Bugreports zur PureBasic 4.0-Beta.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

Code: Alles auswählen

Procedure test() 
   If ExamineDirectory(0, "c:\", "*.*") 
      While NextDirectoryEntry(0) 
         a.q = DirectoryEntrySize(0) 
    Debug a 
      Wend 
   EndIf 
EndProcedure 

test() 
der rückgabewert ist keine float.
mit long gehts auch ohne fehler, aber dann bekommt man bei sehr großen dateien (z.b. dem virtuellen speicher) ein falsches ergebnis.

ok,
1. es steht nicht in der Help
2. die art der fehlermeldung ist seltsam
ich tippe auf irgendein stack-problem, das durch den Rücksprung ausgelöst wird.

ich selber hab da nich so die ahnung von.
evtl. kann ja mal jemand an die version ohne Proc noch ne stack-operation dranhängen, um meine theorie zu überprüfen.

wahrscheinlich ift noch keiner auf das problem gestoßen,
weil man eigentlich nicht auf die idee kommt,
den rückgabewert in ne float zu packen.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Beitrag von PureLust »

Wie Kaeru schon angedeutet hat, wird es wohl tatsächlich an irgendeiner Unverträglichkeit des Rückgabewertes liegen (wird vemutlich ein 8 Byte Quad-Wert sein).

Denn auch mit einem 8 Byte Double-Wert funktioniert es problemlos.
Und auch wenn man eine explizite Umwandlung (durch einfügen eines Operators) druchführt, erhält man keinen Fehler.

Code: Alles auswählen

Procedure TestDouble() 
   If ExamineDirectory(0, "c:\", "*.*") 
      While NextDirectoryEntry(0) 
         a.d = DirectoryEntrySize(0)
    Debug a 
      Wend 
   EndIf 
EndProcedure

Procedure TestFloat() 
   If ExamineDirectory(0, "c:\", "*.*") 
      While NextDirectoryEntry(0) 
         a.f = DirectoryEntrySize(0)+0
    Debug a 
      Wend 
   EndIf 
EndProcedure

Debug TestDouble()
Debug TestFloat()
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

Kaeru Gaman hat geschrieben:mit long gehts auch ohne fehler, aber dann bekommt man bei sehr großen dateien (z.b. dem virtuellen speicher) ein falsches ergebnis.
;)
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
jear
Beiträge: 288
Registriert: 17.10.2004 01:59
Wohnort: Ammerland

Beitrag von jear »

Schlage mich auch gerade mit der Geschichte rum. Irgendwas geht da fürchterlich schief mit den Rückgabewerten, wenn irgendwelche Grenzen überschritten werden.
Allerdings sollten Floats, Doubles und Quads bequem die Zahl von 8.172.071.838 Bytes aufnehmen können, die mein Programmverzeichnis laut Windows groß ist.

Code: Alles auswählen

Structure GetNum
  Files.l
  Dirs.l
EndStructure

;/ rekursive Ermittlung der Gesamtgröße der Dateien ( in Bytes)
;/ in einem Verzeichnisbaum über eine Quad-Variable
Procedure.q DirTreeSize_q(id.l, Directory.s, *Num.GetNum) 
  Protected Name.s
  Protected Size.q, Entry.l
  If ExamineDirectory(id, Directory, "*.*") 
    While NextDirectoryEntry(id) 
      Entry = DirectoryEntryType(id)
      If Entry = #PB_DirectoryEntry_File 
        Size + DirectoryEntrySize(id)
        *Num\Files + 1
      ElseIf Entry = #PB_DirectoryEntry_Directory
        Name = DirectoryEntryName(id) ; Debug Name 
        If Name <> ".." And Name <> "." 
          Size + DirTreeSize_q(id + 1, Directory + Name + "\", *Num.GetNum) 
          *Num\Dirs + 1
        EndIf 
      EndIf 
    Wend
  EndIf 
  ProcedureReturn Size 
EndProcedure

;/ rekursive Ermittlung der Gesamtgröße der Dateien (in Bytes)
;/ in einem Verzeichnisbaum über eine Float-Variable
Procedure.f DirTreeSize_f(id.l, Directory.s, *Num.GetNum) 
  Protected Name.s
  Protected Size.f, Entry.l
  If ExamineDirectory(id, Directory, "*.*") 
    While NextDirectoryEntry(id) 
      Entry = DirectoryEntryType(id)
      If Entry = #PB_DirectoryEntry_File 
        Size + DirectoryEntrySize(id)
        *Num\Files + 1
      ElseIf Entry = #PB_DirectoryEntry_Directory
        Name = DirectoryEntryName(id) ; Debug Name 
        If Name <> ".." And Name <> "." 
          Size + DirTreeSize_f(id + 1, Directory + Name + "\", *Num.GetNum) 
          *Num\Dirs + 1
        EndIf 
      EndIf 
    Wend
  EndIf 
  ProcedureReturn Size 
EndProcedure

;/ rekursive Ermittlung der Gesamtgröße der Dateien (in Bytes)
;/ in einem Verzeichnisbaum über eine Double-Variable
Procedure.d DirTreeSize_d(id.l, Directory.s, *Num.GetNum) 
  Protected Name.s
  Protected Size.d, Entry.l
  If ExamineDirectory(id, Directory, "*.*") 
    While NextDirectoryEntry(id) 
      Entry = DirectoryEntryType(id)
      If Entry = #PB_DirectoryEntry_File 
        Size + DirectoryEntrySize(id)
        *Num\Files + 1
      ElseIf Entry = #PB_DirectoryEntry_Directory
        Name = DirectoryEntryName(id) ; Debug Name 
        If Name <> ".." And Name <> "." 
          Size + DirTreeSize_d(id + 1, Directory + Name + "\", *Num.GetNum) 
          *Num\Dirs + 1
        EndIf 
      EndIf 
    Wend
  EndIf 
  ProcedureReturn Size 
EndProcedure

;Result.q = DirTreeSize_q(0, "C:\Programme\", @Total.GetNum)
Result.f = DirTreeSize_f(0, "C:\Programme\", @Total.GetNum)
;Result.d = DirTreeSize_d(0, "C:\Programme\", @Total.GetNum)
Debug Result
Debug Total\Files
Debug Total\Dirs
Man ist nie zu alt zum lernen, auch wenn man dabei manchmal alt aussieht!
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

> 8.172.071.838

passt noch nicht mal in eine Long, von daher auch nicht in eine Float, ohne ungenau zu werden.

natürlich hast du in sofern recht, dass der rückgabewert der funktion wie jede andere Variable auch sauber ge-cast-et werden müsste.
auch wenn es nicht sinnvoll sein dürfte, den wert mit einem Rundungsfehler zu bekommen.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
HeX0R
Beiträge: 3042
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Beitrag von HeX0R »

Kaeru Gaman hat geschrieben:> 8.172.071.838

passt noch nicht mal in eine Long, von daher auch nicht in eine Float, ohne ungenau zu werden.
*Autsch*
Also diese irrwitzige Aussage solltest du vielleicht doch lieber nochmal überdenken...
Benutzeravatar
jear
Beiträge: 288
Registriert: 17.10.2004 01:59
Wohnort: Ammerland

Beitrag von jear »

Das steckt noch ein mächtiger Bug in PB4 drin, auf den man Fred mal aufmerksam machen sollte.
Für den, den es interessiert, mein Problem habe ich nun so gelöst.

Code: Alles auswählen

Structure GetNum
  Files.l
  Dirs.l
EndStructure

Global NewList TreeMembers.s()

;/ rekursive Ermittlung aller Ordner unter der Root
;/ Ablage der Namen in der Liste TreeMember()
Procedure.l DirTreeMembers(id.l, Directory.s, *Num.GetNum)
  Protected Name.s, Entry.l
  If ExamineDirectory(id, Directory, "*.*") 
    While NextDirectoryEntry(id) 
      Entry = DirectoryEntryType(id)
      If Entry = #PB_DirectoryEntry_Directory
        Name = DirectoryEntryName(id) ; Debug Name 
        If Name <> ".." And Name <> "." 
          Name = Directory + Name + "\"
          AddElement(TreeMembers())
          TreeMembers() = Name
          DirTreeMembers(id+1, Name,*Num.GetNum)
          *Num\Dirs + 1
        EndIf 
      EndIf 
    Wend
  EndIf  
EndProcedure

;/ Ermittlung der Gesamtgröße der Dateien (in KBytes)
;/ in den Verzeichnissen die in der Liste TreeMembers() abgelegt sind
Procedure.l TreeSize(id.l, Directory.s, *Num.GetNum)  
  Protected Name.s
  Protected Size.q, Entry.l 
  DirTreeMembers(0, Directory, *Num.GetNum) 
  ForEach TreeMembers()
    If ExamineDirectory(1, TreeMembers(), "*.*") 
      While NextDirectoryEntry(1) 
        Entry = DirectoryEntryType(1)
        If Entry = #PB_DirectoryEntry_File 
          Size + DirectoryEntrySize(1) : *Num\Files + 1
        EndIf 
      Wend
    EndIf 
  Next
  ClearList(TreeMembers())
  ProcedureReturn Size/1024 
EndProcedure

Result.l = TreeSize(0, "C:\Programme\", @Total.GetNum)

Debug Result
Debug Total\Files
Debug Total\Dirs
Man ist nie zu alt zum lernen, auch wenn man dabei manchmal alt aussieht!
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

HeX0R hat geschrieben:*Autsch*
Also diese irrwitzige Aussage solltest du vielleicht doch lieber nochmal überdenken...
wieso? ist doch logisch.

erklär mir doch mal, wieso ich da falsch liegen soll?
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
HeX0R
Beiträge: 3042
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Beitrag von HeX0R »

Weil Floats ihre 4 Bytes völlig anders benutzen.
Beispielsweise lässt sich eine Zahl:
1.099.511.627.776
kaum in ein Long stopfen, im Float dagegen lässt sie sich problemlos genau (also ohne Fehler) speichern.

Du kannst also bestimmt nicht behaupten keine Zahl, die zu gross für ein Long ist, lässt sich fehlerlos in einem Float speichern.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

HeX0R hat geschrieben:Weil Floats ihre 4 Bytes völlig anders benutzen.
Beispielsweise lässt sich eine Zahl:
1.099.511.627.776
kaum in ein Long stopfen, im Float dagegen lässt sie sich problemlos genau (also ohne Fehler) speichern.

Du kannst also bestimmt nicht behaupten keine Zahl, die zu gross für ein Long ist, lässt sich fehlerlos in einem Float speichern.
:lol:

nagut, für zweierpotenzen gilt da ne ausnahme...
aber du willst doch an der ausnahme keine aussage anpinnen?

in der regel lassen sich zahlen, die nicht in eine long passen, nicht fehlerfrei in einer float speichern.

was ja total logisch ist, weil die noch weniger bits für die mantisse hat, weil sie auch welche für den exponenten braucht.

und um als beispiel mal die zahl zu nehmen, die von jear genannt und von mir zitiert wurde:

Code: Alles auswählen

a.q = 8172071838
b.l = a
c.f = a
Debug a
Debug b
Debug c
sehen heißt glauben. ;)

----------------------------------------------------
PS:
statistik:
2^64 = 18446744073709551616 (window-calc, keine garantie)
2^23 = 00000000000008388608
die differenz liegt immer noch wesentlich über 18Trillionen.
von diesen sind nur (64-23)= 41 zahlen genau Zweierpotenzen,
lassen sich also fehlerfrei darstellen.
Das ist noch nicht mal ein gottverdammter Meßfehler!
und damit willst du meine Aussage in Zweifel ziehen?
GEH HEIM!
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Gesperrt