byterechner() - Bytes in größtmögliche Einheit umrechnen

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

@Kaeru:
Falscher Thread?

@all:
Kann mir jemand sagen, warum ich sogar hier einen bescheuerten Fehler
bekomme? Ich glaube Purebasic ist bei Doubles und Quads in Procedures noch ziemlich verbugt.

Außerdem funktioniert das hier nicht:

Code: Alles auswählen

unit = 1
Debug PeekS(@"KBMBGBTBPBEBZBYB" + 1 * 2, 2)
Debug PeekS(@"KBMBGBTBPBEBZBYB" + unit * 2, 2)
An diesem Code ist nichts falsch, trotzdem gibt es zwei Bugs...

Code: Alles auswählen

Procedure.s ByteCalc(Bytes.d, NbDecimals.l = 0)
  Protected result.s, unit.l
  
  unit = Round(Log(Bytes) / Log(1024), 0)
  Bytes / Pow(1024, unit)
  
  If unit
    result = StrD(Bytes, NbDecimals) + " " + PeekS(@"KBMBGBTBPBEBZBYB" + unit * 2 - 2, 2)
  Else
    result = StrD(Bytes, 0) + " B"
  EndIf
  
  ProcedureReturn result
EndProcedure

Debug ByteCalc(21456985147)
Debug ByteCalc(21456985147, 1)
Debug ByteCalc(21456985147, 2)
Debug ByteCalc(21456985147, 4)
Debug ByteCalc(1024 * 1024 - 500, 4)
Debug ByteCalc(512, 1)
Wenn es bei irgendjemandem laufen sollte,
dann liegt es wirklich an irgend einer fehlerhaften Konfiguration von mir.
Aber probiert erstmal aus.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Bist sicher, das dies Korrekt ist:

Code: Alles auswählen

PeekS(@"KBMBGBTBPBEBZBYB" + unit * 2 - 2, 2)
Illegal Instruction (executing binary data?) :mrgreen:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Ja, das ist korrekt. Schonmal meinen ersten Code getestet? Da funktioniert
der Codeschnipsel mit Konstanten, aber nicht mit Variablen.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Stimmt, mit Variable bleibts leer, erste Zeile geht, zweite geht mit Konstanten
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

NicTheQuick hat geschrieben:Wenn es bei irgendjemandem laufen sollte,
dann liegt es wirklich an irgend einer fehlerhaften Konfiguration von mir.
Aber probiert erstmal aus.
Bei mir gibt's nen invalid Memory Access in Zeile 13 (Bei ProcedureReturn).

Aber kannst du nicht einfach mit Mid() arbeiten oder hast du's jetzt auf die volle Performance abgesehen? :wink:
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Ja, stimmt, Mid() gibt es ja auch noch. :wink:

Aber dennoch gibt es hier schon wieder einen Bug:

Code: Alles auswählen

Procedure.s ByteCalc(Bytes.d, NbDecimals.l = 0)
  Protected result.s, unit.l
  Static Suffix.s = "KBMBGBTBPBEBZBYB"
  
  unit = Round(Log(Bytes) / Log(1024), 0)
  Bytes / Pow(1024, unit)
  
  If unit
    Debug unit
    result = StrD(Bytes, NbDecimals) + " " + Mid(Suffix, unit * 2 - 1, 2)
  Else
    result = StrD(Bytes, 0) + " B"
  EndIf
  
  ProcedureReturn result
EndProcedure
Wenn man den Inhalt von Suffix direkt bei Mid() einsetzt, funktioniert es
wieder.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Tja... Hätt'ste mich ned, hätt'ste Mid nich... :wink:

Tipp: Warum Suffix als Staic deklarieren? :shock: Tut es da nicht auch ein Prot... Hm... Aha, Wenn als Static deklariert, muss es nächstes Mal nicht wieder deklariert werden. genial :allright:

Aber warum setzt du Suffix nicht trotzdem bei Mid() direkt ein?
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

[OT]
NicTheQuick hat geschrieben:@Kaeru:
Falscher Thread?
Kaeru Gaman hat geschrieben:...darum ging es mir. man kann nichts aussagen über die performance von ausdrücken,
solange man nicht weiß, wie sie im endeffekt bei der CPU landen.
ts-soft hat geschrieben:Solange keine Progressbar erforderlich ist :mrgreen: , spielt es wohl eher
eine untergeordnete Rolle
Kaeru Gaman hat geschrieben:hä?

was hattn jetzt Radio Eriwan mit der Chinesischen Kulturrevolution zu tun?
[/OT]
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Kleiner und schneller geht es gar nicht mehr! :D Jetzt sind wir schon im Elite-bereich angelangt.
Von NickTheQuick inspiriert, habe ich die Log() Idee übernommen - damit es nicht einfach nur abschreiben/abkupfern ist, habe ich mich hingesetzt und nochmal nachgeschaut, was log() bewirkt. Dafür hat NtQ von mir ja auch den Tipp mit Mid() bekommen. :allright:

Code: Alles auswählen

Procedure.s byterechner(byte.q, NbDecimals.b=0) 
   Protected bytes.d=PeekQ(@byte), unit.b=Round(Log(bytes)/Log(1024), 0) 
   ProcedureReturn StrD(Bytes/Pow(1024, unit), NbDecimals*(unit > 0 And 1))+" "+StringField("Byte,KB,MB,GB,TB,PB,EB", unit+1, ",") 
EndProcedure
  • Kleine Verbesserung vorgenommen.
Nur 4 Zeilen Code! Wahnsinn... Davon hätt ich anfangs nur träumen können... :D :allright:


Procedure vs. Macro
Man kann es natürlich als Einzeiler verpacken - hab ich getan. Dann habe ich jeweils diesen Zweizeiler und den Einzeiler nochmal als Macro notiert und alle 4 Versionen 50.000 und 100.000 Mal durchlaufen lassen.
Nachteil bei dem Zweizeiler-Mackro: Man muss mit einer Variablen arbeiten, die nicht wie bei der Procedure protected werden kann.
  • Ergebnisse bei 100.000 Durchläufen auf einem System mit 550 MHz/XP mit der Zahl 5415756379 und 1 nachkommastelle:
    Procedure, 2 Zeiler: 2093 ms
    Procedure, 1 Zeiler: 2474 ms
    Makro, 2 Zeiler: 1722 ms <--- Sieger
    Makro, 1 Zeiler: 1833 ms
Dennoch finde ich die 2 Zeiler Prozedur am besten. Den 2er Makro, der zwar am schnellsten ist, kann nämlich nicht bequem in IF-Abfragen beispielsweise eingebaut werden. Außerdem können Makros generell keine Werte zurückgeben. Makro-Ergebnisse müssen immer in Variablen zwischengespeichert werden. Hingegen vergrößern Procedures nicht den Quellcode und sind einfacherer handzuhaben.
Zuletzt geändert von AND51 am 31.10.2006 20:32, insgesamt 3-mal geändert.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Und wieder mein beliebter Fehler:
Debugger hat geschrieben:Line: 3 - Illegal instruction. (executing binary data?)
Warum hab ich den Fehler wieder und sonst keiner?

Bei mir funktionert es nur ohne das PeekQ(). Jetzt hab ich es aber wohl oft
genug gesagt. :mrgreen:

@AND51: Wieso hast du deine eigene Idee mit Mid() nicht selbst benutzt?
Ich wette, damit ist es sogar noch schneller, weil nicht nach Kommas
gesucht werden muss.

Code: Alles auswählen

Procedure.s byterechner(Byte.q, NbDecimals.l = 0)
   Protected Bytes.d = Byte, unit.l = Round(Log(Bytes) / Log(1024), 0)
   ProcedureReturn StrD(Bytes / Pow(1024, unit), NbDecimals * (unit => 1 And 1)) + " " + Mid("KBMBGBTBPBEB", unit * 2 - 1, 2)
EndProcedure

Debug byterechner(1024 * 1024 - 512, 2)
@all: Und denkt dran. In Doubles passen die Zahlen nicht so genau rein
wie in Quads.
Antworten