Seite 1 von 6

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

Verfasst: 11.10.2006 12:42
von AND51
Wichtig!
Auf Seite 6 gibt es ein Update, welches etwas schneller ist, als der "Gewinner" (Gott, klingt das eingebildet) des deutschen Contests!
»»» Gehe zu Seite 6

Das Update benutzt auch keine 'booleschen Ausdrücke' mehr, diese werden offiziell nämlich nicht unterstützt!

———————————————————————————————————————

Hallo!

Edit: Hier habe ich den Code mal nach vorn geholt und gleichzeitig nocheinmal verbessert. (Update: 0 Byte wurden als 1- byte umgerechnet, Fehler behoben)

Code: Alles auswählen

Procedure.s byterechner(byte.q, NbDecimals.l=0)
	Protected unit.l
	If byte
		unit=Round(Log(byte)/Log(1024), 0)
	EndIf
	ProcedureReturn StrD(byte/Pow(1024, unit), NbDecimals*(unit And 1))+" "+StringField("Byte,KB,MB,GB,TB,PB,EB", unit+1, ",")
EndProcedure

Debug byterechner(-4096) ; ungültige Angabe wird zu "-1 Byte"
Debug byterechner(0) ; Eine Null-Byte große Datei bleibt auch 0 Byte groß :)
Debug byterechner(27101988) ; Bisherige Angaben bleiben ok
  • Funktionstüchtig mit PB 4.01+
    Beschreibung: Geht bis 8.999.999.999.999.999.999 Byte (7,8 EB)

Hier meine neue PB 4 Byterechner Prozedur.
rechnet beliebige Anzahl an Bytes mit Hilfe des neuen Types Quad in die größtmögliche Einheit um. Wer weiß schon, wie viel 4096096 Byte in KB sind?^^

Wer mag, kann ja die Prozedur erweitert hier posten, sodass ein oder zwei Stellen hinter dem Komma unrerstützt werden. Ich habe ein bisschen mit Modulo versucht, aber sofort die Krise gekriegt. Wäre an der extended Version interessiert :allright:
Meine Version rundet nämlich ab, weil es ja alles hinterm Komma weglässt.

Meine ältere Version des Byterechners arbeitete mit Floats, die Prozedur fliegt ie im Forum irgendwo noch rum. Diese unterstützte Kommazahlen, konnte dafür aber nicht so weit wie diese hier rechnen.

Code: Alles auswählen

Procedure.s byterechner(byte.q)
	Protected einheit.s
	
	If byte < 1024
		ProcedureReturn Str(byte)+" Byte"
	EndIf
	If byte >= 1024
		byte/1024
		einheit.s=" KB"
	EndIf
	If byte >= 1024
		byte/1024
		einheit.s=" MB"
	EndIf
	If byte >= 1024
		byte/1024
		einheit.s=" GB"
	EndIf
	If byte >= 1024
		byte/1024
		einheit.s=" TB"
	EndIf
	If byte >= 1024
		byte/1024
		einheit.s=" PB"
	EndIf
	If byte >= 1024
		byte/1024
		einheit.s=" EB"
	EndIf
	
	ProcedureReturn Str(byte)+einheit.s
EndProcedure

Debug byterechner(4096096) ; 3 MB
Debug byterechner(1024) ; 1 KB 
Debug byterechner($FFFFFF) ; 15 MB
Debug byterechner(21456985147) ; 19 GB

Verfasst: 11.10.2006 13:22
von nco2k

Code: Alles auswählen

Procedure.s ByteCalc(Value.q, NbDecimals.b = 0)
  Result.s = ""
  Bytes.d = PeekQ(@Value)
  If Bytes => 0 And NbDecimals => 0
    Unit.b = 0
    While Unit < 6 And Bytes => 1024
      Bytes / 1024
      Unit + 1
    Wend
    Result = StrD(Bytes, NbDecimals)
    Select Unit
      Case 0
        Result = StrD(ValD(Result), 0)+" Byte"
      Case 1
        Result+" KB"
      Case 2
        Result+" MB"
      Case 3
        Result+" GB"
      Case 4
        Result+" TB"
      Case 5
        Result+" PB"
      Case 6
        Result+" EB"
    EndSelect
  EndIf
  ProcedureReturn Result
EndProcedure

Debug ByteCalc(21456985147)
Debug ByteCalc(21456985147, 1)
Debug ByteCalc(21456985147, 2)
Debug ByteCalc(21456985147, 4)
c ya,
nco2k

Verfasst: 11.10.2006 13:33
von AND51
Danke schon mal für deinen Post!

Allerdings arbeitest du mit Doubles, ist da nicht der Wertebereich etwas beschränkt? Trotzdem: So hatte ich es auch vorher.

Das hochzählen mit den Units finde ich übrigens richtig elegant <)

Verfasst: 11.10.2006 13:55
von nco2k
@AND51
> Allerdings arbeitest du mit Doubles, ist da nicht der Wertebereich etwas beschränkt?
hm.. eigentlich nicht. ich verwende ja sowohl quads als auch doubles und ich wüsste jetzt nicht wirklich, wie ich auf eine ungerundete nachkommastelle kommen soll, ohne floats/doubles zu verwenden.

c ya,
nco2k

Verfasst: 11.10.2006 14:10
von NicTheQuick
Das mit dem Bytes = PeekQ(@Value) hat bei mir bei ProcedureReturn
irgendeinen Fehler verursacht. Außerdem waren die Variablen lokal nicht
geschützt. Zusätzlich hab ich das Gewirr hinter Case 0 abgeändert.

Hier also meine Version:

Code: Alles auswählen

Procedure.s ByteCalc(Value.q, NbDecimals.l = 0)
  Protected result.s = "", Unit.l = 0, Bytes.d = Value
  
  If Bytes => 0 And NbDecimals => 0
    While Unit < 6 And Bytes => 1024
      Bytes / 1024
      Unit + 1
    Wend
    result = StrD(Bytes, NbDecimals)
    Select Unit
      Case 0 : result = StrQ(Value) + " Byte"
      Case 1 : result + " KB"
      Case 2 : result + " MB"
      Case 3 : result + " GB"
      Case 4 : result + " TB"
      Case 5 : result + " PB"
      Case 6 : result + " EB"
    EndSelect
  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)

Verfasst: 11.10.2006 14:15
von AND51
OK, ich schau noch mal nach.

Habe zwischenzeitlich deine prozedur etwas zusammengestampft:

Code: Alles auswählen

Procedure.s byterechner(byte.q, NbDecimals.c=0)
	Protected res$, bytes.d=PeekQ(@byte), unit.c
		While unit < 6 And Bytes > 1023
			bytes/1024
			unit+1
		Wend
		If unit
			res$=StrD(bytes, NbDecimals)+" "+StringField("KB,MB,GB,TB,PB,EB,ZB,YB", unit, ",")
		Else
			res$=StrD(bytes, 0)+" Byte"
		EndIf
	ProcedureReturn res$
EndProcedure
Ist das so nicht übersichtlicher?

Gleichzeitig sind die Variablen noch protected und es sind statt 127 nun 255 Nachkommastellen möglich falls irgend ein :freak: auf die Idee kommt :)


Edit: Oh, noch ein Konkrrent und Gleichgesinnter <)
Aber wozu brauche ich
  • Protected result.s = ""
? Der String ist anfangs doch eh null-initalisiert :wink:


btw. Bei mir verursacht das PeekQ() keinen Fehler.

Verfasst: 11.10.2006 14:22
von NicTheQuick
@AND51:
Dieses blöde Ding gibt bei mir einen "Invalid Memory Access" in Zeile 8: Bytes.d=PeekQ(@Byte)

Wieso nicht so: Bytes.d = Byte ???

///Edit zum Edit von AND51:
Ohne PeekQ() geht es einwandfrei, also warum so umständlich?

Klar, das result.s = "" kann man weglassen, ein result.s reicht vollkommen.
Ich hab das so geschrieben, weil es vorher auch schon so da gestanden hat.

Verfasst: 11.10.2006 14:23
von ts-soft
NicTheQuick hat geschrieben:Das mit dem Bytes = PeekQ(@Value) hat bei mir bei ProcedureReturn
irgendeinen Fehler verursacht.
Den Fehler hab ich bei Deiner Version :freak:
nco2 seine Version geht einwandfrei.
Haste vielleicht eine alte Lib oder sowas?

Verfasst: 11.10.2006 14:25
von nco2k
@NicTheQuick
> PeekQ
ich hab PeekQ geschrieben weil irgendwo ein quad bug in pb shlummert der einen ima verursacht wenn ich Bytes.d = Value schreibe. komisch dass es bei dir andersrum ist.

> Protected
ich verwende nie protected da ich jeden code in prozeduren verpacke und ausserhalb von prozeduren keine variablen etc. rumliegen.

im endeffekt hast du den code nur deinem style angepasst, was absolut geschmackssache ist. ich persönlich hasse es Case 0 : ... zu schreiben.

@AND51
hab noch nie StringField() verwendet, nette idee.

c ya,
nco2k

Verfasst: 11.10.2006 14:33
von AND51
Jetzt bin ich auf jeden Fall Spitzenreiter mit nur 8 Zeilen: :D
Arbeite auch ganz ohne Strings und spart in der While-Zeile auch noch 1 Byte, indem ich >= 1024 durch > 1023 ersetze. Rein theorethisch müsste diese Ersetzung sogar einen -wenn auch minimalen- Performanceschub bringen, oder?

Code: Alles auswählen


; LEICHT FEHLERBEHAFTET - Siehe nächsten Post für korrigierte Version

Procedure.s byterechner(byte.q, NbDecimals.c=0)
	Protected bytes.d=PeekQ(@byte), unit.c=1
		While unit < 6 And bytes > 1023
			bytes/1024
			unit+1
		Wend
		ProcedureReturn StrD(bytes, NbDecimals*(Not (NbDecimals And bytes < 1024)))+" "+StringField("Byte,KB,MB,GB,TB,PB,EB", unit, ",")
EndProcedure
Ich habe mich auch gefragt: Warum PeekQ(). OK, wer's braucht, lässt's, wer's nicht braucht, streicht es und spart 5 Byte :wink:

@ nco2k: Danke! Ich könnte mir ein Leben ohne Stringfield() allerdings nicht mehr vorstellen... :lol: