Seite 2 von 3

Verfasst: 25.09.2007 22:42
von Kaeru Gaman
ne denk doch mal nach....

Float benutzt 4 byte, Long benutzt 4 byte.
Float benutzt ein paar Bit für den Exponenten, Long nicht, das ist Ganzzahl.
die Information ist begrenzt auf 2^32 verschiedene zustände.
mehr kann man nicht speichern.

im Bereich von 0 bis 2147483647 ist Long absolut genau.
aber Float kann 2147483647.0 schon nicht mehr genau darstellen,
weil ein paar Bit für den Exponenten benutzt werden.

demo:

Code: Alles auswählen

a.f = 2147483600
b.l = 2147483600
Debug a
Debug b
a+1
b+1
Debug a
Debug b
a+1
b+1
Debug a
Debug b
siehst du?
nicht nur, dass Float die Zahl beim ersten aufruf ungenau wiedergibt,
es ist nicht fähig, eine kleine addition zu verarbeiten.

das liegt nicht an PB, das liegt an der Natur der Fließkommazahlen.
der selbe Algorithmus wird dir in C++ oder Java oder wo auch immer
das selbe Ergebnis liefern, wenn du einen 32bit-variablen-typ wählst.

mit 64bit (Double) kannst du das Problem verlagern, aber nicht eliminieren.

Verfasst: 25.09.2007 23:28
von Agent
So, ich hab die Routine mal auf Quad umgestellt (und unsinniges rausgenommen):

Code: Alles auswählen

Procedure SK_CopyFile(sourcefile$, targetfile$, OverwriteExistingFile.b=#True, *ProgressRoutine.l=0, qPackSize.q=0)
  
  ; Definitionen
  Define.q qSourceFileLen, qSourceFilePos, qPackSize
  Define.q *CopyBuffer, qDataReaded
  Define.l lSourceFile, lTargetFile, lResult
  Define.l Memory.MEMORYSTATUS  

  ; Rückgabe-Codes definieren
  #SK_CopyFile_Failed             = 0 ; #False
  #SK_CopyFile_OK                 = 1 ; #True
  #SK_CopyFile_0ByteFile          = 2 ; Quell-Datei ist 0 Byte groß
  #SK_CopyFile_UserAbort          = -1 ; User hat abgebrochen
  #SK_CopyFile_FileNotFound       = -2 ; Quell-Datei nicht gefunden
  #SK_CopyFile_CannotOpenSource   = -3 ; Konnte Quelle nicht öffnen
  #SK_CopyFile_CannotCreateTarget = -4 ; Konnte Zieldatei nicht anlegen
  #SK_CopyFile_TargetCorrupt      = -5 ; Source-Size und Target-Size sind unterschiedlich. Ggf, Speicher voll.
  #SK_CopyFile_MemoryError        = -6 ; Konnte Speicher nicht reservieren
  
  ; Standard-Wert für Rückgabe: Fehler!
  lResult=#SK_CopyFile_Failed


  ; Progress-Routine (Aufbaubeispiel)
        ; Procedure SK_CopyFile_ProgressCallback(act_pos.q, filesize.q)
        ;   If filesize>0
        ;     percentage_done = (act_pos*100)/filesize
        ;   Else
        ;     percentage_done = 100
        ;   EndIf
        ;   SetGadgetState(#main_progressbar_file, percentage_done)
        ; EndProcedure
  
  ; Gibt es Zieldatei schon: User fragen wie es weiter gehen soll!
  If FileSize(targetfile$)>0 And OverwriteExistingFile=#False ; Ziel existiert, User will gefragt werden!
    If MessageRequester("","Möchten Sie folgende Datei überschreiben?"+#CRLF$+#CRLF$+targetfile$, #PB_MessageRequester_YesNo) = #PB_MessageRequester_No
      ProcedureReturn #SK_CopyFile_UserAbort
    EndIf      
  EndIf
  
  ; Quelle öffnen
  lSourceFile = OpenFile(#PB_Any, sourcefile$)   
  qSourceFilePos = 0
    
  If IsFile(lSourceFile) ; Quelle öffnen ok?
    
    ; Zieldatei erzeugen
    lTargetFile = CreateFile(#PB_Any, targetfile$)
    
    If IsFile(lTargetFile) ; Ziel öffnen ok?
      
      ; Wieviel arbeit liegt vor uns
      qSourceFileLen=Lof(lSourceFile) ; Dateigröße ermitteln
      
      If qSourceFileLen > 0 ; Quelle eine 0-Byte-Datei?
        
        ; Paketgröße ermitteln
        If qPackSize = 0 ; Dynamische Paketgröße              
          GlobalMemoryStatus_(Memory.MEMORYSTATUS)
          If qSourceFileLen < 3145728 ; 3 MB
            qPackSize = qSourceFileLen
          ElseIf (qSourceFileLen/100) < (Memory\dwAvailPhys / 4)
            qPackSize = qSourceFileLen / 100
          Else
            qPackSize = (Memory\dwAvailPhys / 1000)
          EndIf
        EndIf
        
        ; Falls ProgressCallback: Startwert eintragen, damit User sieht es passiert was
        If *ProgressRoutine <> 0
          CallFunctionFast(*ProgressRoutine, 1, qSourceFileLen)
        EndIf

        ; Speicher reservieren für Blocks...
        *CopyBuffer = AllocateMemory(qPackSize)
        
        If *CopyBuffer ; Speicher ok? Dann los!
        
          Repeat
            
            ; Daten aus Quelle einlesen
            qDataReaded = ReadData(lSourceFile, *CopyBuffer, qPackSize)
            
            If qDataReaded > 0 ; Daten korrekt gelesen? Dann ab in die Zieldatei
              WriteData(lTargetFile, *CopyBuffer, qDataReaded)                
              qSourceFilePos + qDataReaded                
            ElseIf qDataReaded = 0 And qSourceFilePos < qSourceFileLen ; Ui, da ging was schief
              lResult = #SK_CopyFile_Failed
            EndIf
          
            ; Progress aktualisieren
            If (*ProgressRoutine <> 0) And (qDataReaded > 0) And (qSourceFilePos < qSourceFileLen)
              CallFunctionFast(*ProgressRoutine, qSourceFilePos, qSourceFileLen)
            EndIf
            
          Until qSourceFilePos >= qSourceFileLen Or qDataReaded=0 Or bGlobalAbort=#True Or bMainExit=#True
    
          If bGlobalAbort = #True ; Hat User abgebrochen?
            lResult = #SK_CopyFile_UserAbort
          EndIf
          
          If qSourceFileLen <> qSourceFilePos ; Gibts Probleme mit den Dateigrößen? Differenzen?
            lResult = #SK_CopyFile_TargetCorrupt
            Debug "Source <> Target"
          EndIf
                      
          ; Speicher wieder freigeben!
          FreeMemory(*CopyBuffer)
          
        Else
          lResult = #SK_CopyFile_MemoryError ; Probleme beim Speicher reservieren
        EndIf
        
      Else
        lResult = #SK_CopyFile_0ByteFile ; War ne 0-Byte-Datei
      EndIf
      
      ; Zieldatei wieder schließen
      CloseFile(lTargetFile)

    Else
      lResult = #SK_CopyFile_CannotCreateTarget ; Zieldatei konnte nicht angelegt werden
    EndIf
    
    ; Quelldatei wieder schließen
    CloseFile(lSourceFile)      
          
    ; Datum und Attribute wie Originaldatei setzen
    SetFileDate(targetfile$, #PB_Date_Created, AddDate(GetFileDate(sourcefile$, #PB_Date_Created), #PB_Date_Hour, UTC_Korrektur))
    SetFileDate(targetfile$, #PB_Date_Modified, AddDate(GetFileDate(sourcefile$, #PB_Date_Modified), #PB_Date_Hour, UTC_Korrektur) )      
    SetFileAttributes(targetfile$, GetFileAttributes(sourcefile$)) ; Attribute angleichen

    ; Progress lieber nochmal auf 100% setzen
    If *ProgressRoutine <> 0
      CallFunctionFast(*ProgressRoutine, qSourceFileLen, qSourceFileLen)
    EndIf
        
    lResult = #SK_CopyFile_OK ; Super, alles ok
  Else
  
    lResult = #SK_CopyFile_CannotOpenSource ; Quelle konnte nicht geöffnet werden :(
  EndIf
    
  ProcedureReturn lResult
EndProcedure
Jetzt bricht die Routine bei

Code: Alles auswählen

qDataReaded = ReadData(lSourceFile, *CopyBuffer, qPackSize)
ab, mit dem Fehler: #File object not initialized.

Wie das denn? Datei ist definitiv offen. Geprüft mit IsFile(). Mit floats oder longs ging das noch. Das war auch der Grund warum ich von ursprünglich Quad wieder weg bin. Früher war die Routine mal mit Quads. Aber genau da lag das Problem. :(

Verfasst: 26.09.2007 00:24
von Kaeru Gaman
welcher PB-version?

die Quads sind in 4.00 neu gekommen, und waren noch nicht komplett ausgereift.
ein paar quad-fehler sind auch in der 4.02 stable noch drin.
in der 4.10 beta sind sie aber behoben.

das nur mal auf die schnelle, ich hab deinen code jetzt nicht nach Human-Bugs auseinandergepflückt....

Verfasst: 26.09.2007 09:21
von Agent
Hi.

PB v4.02.
Habe noch ein wenig experimentiert und die zu lesenende Puffergröße mal auf ein max. von LONG gestellt, da ich hier das Problem vermutete. Nutzlos.

ReadData() arbeitet nicht, wenn der Rückgabewert in eine QUAD geschrieben werden soll.

Verfasst: 26.09.2007 09:35
von HeX0R
Mit PB4.1B3 funktioniert dein Code Wonderbra!

Allerdings würde ich vorschlagen Variablen in Prozeduren nicht zu "definen", sondern zu Protecten:

Code: Alles auswählen

; Definitionen
  Protected qSourceFileLen.q, qSourceFilePos.q
  Protected *CopyBuffer, qDataReaded.q
  Protected lSourceFile.l, lTargetFile.l, lResult.l
  Protected Memory.MEMORYSTATUS
Define macht eher Sinn ausserhalb von Prozeduren.

Verfasst: 26.09.2007 10:55
von Agent
Negativ.

Habe gerade die v4.10B3 upgedated. Code bleibt an gleicher Stelle stehen o.O.

Verfasst: 26.09.2007 11:52
von HeX0R
Tatsächlich ?
Wie gross ist denn die Datei, die du kopieren willst ?
Ich habs natürlich nur mal mit ner Furzdatei versucht.

Verfasst: 26.09.2007 11:55
von Agent
Das scheint mir keine Rolle zu spielen... Beim 1. zugriff gibts schon Probleme...

Verfasst: 26.09.2007 11:56
von HeX0R
Benutzt du einen Callback ?
Bzw. ginge es ohne den ?

Verfasst: 26.09.2007 11:57
von Agent
Mit Callback