amiga-news ENGLISH VERSION
.
Links| Forum| Kommentare| News melden
.
Chat| Umfragen| Newsticker| Archiv
.

amiga-news.de Forum > Programmierung > Partionsgröße in 64 Bit [ - Suche - Neue Beiträge - Registrieren - Login - ]

-1- [ - Beitrag schreiben - ]

14.08.2007, 22:57 Uhr

MaikG
Posts: 5172
Nutzer
Ich hab einen C-Code, der macht für kleine Partitionen korrekte
Werte, für große nicht.
Da war was mit NSD und TD64. Also müsste man jetzt alles ändern
oder geht das irgendwie indem man eine 64 Bit Variable verwendet?
Im letzteren falle wie? Der Compiler wird sowas vermutlich nicht
direkt unterstützten weil der alt ist.

code:
if (lock=Lock(file,SHARED_LOCK)) {
        if (Info(lock,idata)) {
            usedbytes=idata->id_NumBlocksUsed*idata->id_BytesPerBlock;
            totalbytes=idata->id_NumBlocks*idata->id_BytesPerBlock;
            apu1=totalbytes>>10;
            if(apu1) percent=(usedbytes>>10)*100/apu1;
            ret=1;
        }
        UnLock(lock);
    }


Also in Kilobytes oder Megabytes würde mir das reichen.
Da müsste man doch irgendwie die Multiplikation mit einer division
um 1024 ergänzen können und damit den ULONG bereich nicht überschreiten.
Aber ich brauch auch prozent, das mit dem Shiften verstehe ich
da nicht.

[ Dieser Beitrag wurde von MaikG am 14.08.2007 um 23:52 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 08:52 Uhr

thomas
Posts: 7717
Nutzer
Die MB kannst du so herausfinden:

blocks_per_mb = 1024*1024 / BytesPerBlock;
disk_size = NumBlocks / blocks_per_mb;
used_mb = NumBlocksUsed / blocks_per_mb;
free_mb = disk_size - used_mb;

Das setzt voraus, daß die Disk größer ist als ein MB und eine Blockgröße hat, die ein MB ganzzahlig teilt.

Das kannst du natürlich auch mit KB machen, aber Blöcke größer als ein KB sind durchaus nicht selten und damit funktioniert das nicht (die erste Division ergibt dann 0).

Zitat:
oder geht das irgendwie indem man eine 64 Bit Variable verwendet

Klar. Wenn dein Compiler 64bit-Variablen unterstützt (das kann meines Wissens nur der GCC), dann kannst du deine Variablen einfach als long long oder unsigned long long deklarieren und hast keine Probleme mehr.

Zitat:
das mit dem Shiften verstehe ich da nicht.

Der rechnet halt mit KB. Ersetze >> 10 einfach durch / 1024. Die 1024 kannst du dann rauskürzen.

Gruß Thomas

--
Email: thomas-rapp@web.de
Home: thomasrapp.homepage.t-online.de/

[ Dieser Beitrag wurde von thomas am 15.08.2007 um 08:56 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 09:49 Uhr

MaikG
Posts: 5172
Nutzer
>Das setzt voraus, daß die Disk größer ist als ein MB und eine
>Blockgröße hat, die ein MB ganzzahlig teilt.

Das ist schlecht. Einmal kann es sich auch um z.B. 880kB handeln und
das mit dem Teilen ergibt das nur einen ungenauen oder falschen wert?


>Das kannst du natürlich auch mit KB machen, aber Blöcke größer als
>ein KB sind durchaus nicht selten und damit funktioniert das nicht
>(die erste Division ergibt dann 0).

Es kann im gesamten Amiga-gültigen bereich liegen.


>Klar. Wenn dein Compiler 64bit-Variablen unterstützt (das kann
>meines Wissens nur der GCC), dann kannst du deine Variablen
>einfach als long long oder unsigned long long deklarieren und hast
>keine Probleme mehr.

SASC ist älter als GCC und vbcc und fällt damit wohl aus.


>Der rechnet halt mit KB. Ersetze >> 10 einfach durch / 1024. Die 1024 kannst du dann rauskürzen.

Eigentlich müssten das Bytes gewesen sein, weil später kommt noch eine
fallunterscheidung wo dann Bytes>Kbytes werden wenn >1024 und
das selbe dann noch in MB.

Ja nun müsste ich praktisch auch sowas ähnliches machen, aber
woher weiss ich vorher ohne den ULONG bereich zu überschreiten
ob die Disk als Bytes, Kbytes oder Mbytes anzugeben ist?

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 10:59 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von MaikG:
Aber ich brauch auch prozent, das mit dem Shiften verstehe ich
da nicht.

Dann lass es weg. Wie berechnet man Prozentwerte? Aktueller Werte geteilt durch Grundwert mal hundert. Also:
C code:
if (lock=Lock(file,SHARED_LOCK)) {
    if (Info(lock,idata)) {
      percent=idata->id_NumBlocksUsed*100/idata->id_NumBlocks;
      ret=1;
    }
    UnLock(lock);
  }

Die Blöckgröße spielt für die prozentuale Auslastung überhaupt keine Rolle. Sie steht ja auch in Deiner Fassung auf beiden Seiten des Bruchstrichs.

Jetzt hast Du nur noch das Problem, dass die Anzahl der Blöcke sehr groß sein und idata->id_NumBlocksUsed*100 einen Überlauf erzeugen könnte. Da C so eine grottige Sprache ist, die Dir das nicht mitteilt (obwohl die CPU das jedesmal überprüft und im Flag-Register anzeigt), musst Du vorher eine Fallunterscheidung machen.
C code:
if (lock=Lock(file,SHARED_LOCK)) {
    if (Info(lock,idata)) {
      unsigned int used=idata->id_NumBlocksUsed, max=idata->id_NumBlocks, largest=~0;
      if(largest/100 < used) // potential overflow
        percent=used/(max/100);
      else
        percent=used*100/max;
      ret=1;
    }
    UnLock(lock);
  }

Die Berechnungvariante für große Zahlen verursacht keinen Überlauf, würde aber bei kleinen Zahlen zu Rundungsfehlern führen. Deshalb die Fallunterscheidung.

mfg

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 11:15 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von MaikG:
Also in Kilobytes oder Megabytes würde mir das reichen.

Ok. Problem Nr. 2.

Das ist eigentlich dem Prozentproblem ähnlich. Du vermeidest Überlaufe am leichtesten, in dem Du die zugehörigen Berechnungen vermeidest. Wenn Du die Größe in kB oder MB angeben möchtest, dann rechne die Größe in bytes, die einen Überlauf verursachen könnte, gar nicht erst aus.

Die kleinste zulässige (und am häufigsten benutzte) blockgröße ist 512 bytes, also ein halbes kB. In diesem Fall musst Du die Anzahl Blöcke nur durch zwei teilen und Du hast die Angabe in kB. Ansonsten ermittle den Faktor, der durch die Blockgröße bestimmt wird, und benutze ihn. Allerdings kann bei großen Blöcken auch ein Überlauf stattfinden, dann kommst Du um 64 Bit Arithmetik nicht herum.

Hier erst mal die einfache Variante:
C code:
if(lock=Lock(file,SHARED_LOCK)) {
  if(Info(lock,idata)) {
    switch(idata->id_BytesPerBlock) {
      unsigned int blockFactor; // half kB
      case 512: // mostly used
        usedkB=idata->id_NumBlocksUsed>>1; // num/2
        totalkB=idata->id_NumBlocks>>1;
      case 1024: // not so common, but easy to optimize
        usedkB=idata->id_NumBlocksUsed;
        totalkB=idata->id_NumBlocks;
      default:
        blockFactor=idata->id_BytesPerBlock/512;
        usedkB=(idata->id_NumBlocksUsed*blockFactor)>>1;
        totalkB=(idata->id_NumBlocks*blockFactor)>>1;
    }
    ret=1;
  }
  UnLock(lock);
}


Das kommt ohne 64 Bit Arithmetik aus, hat allerdings einen Überlauf bei Größen ab 2147483647,5 kB also 2048 GB großen Partitionen.

Wenn ich mich jetzt nicht verrechnet habe.

mfg

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 11:23 Uhr

MaikG
Posts: 5172
Nutzer
Das mit Prozent klingt schon ganz gut, aber muss das nicht
ULONG heissen?

Okay, ich hab jetzt mal folgendes gemacht, das Ergebniss
von (totalbytes/1024)*BlocksperTrack in einer Double - die
kann ja 8 Byte erfassen.
Dann eine fallunterscheidung, je nachdem ob es einen Overflow
gibt oder nicht die Normale Routine oder ebend gleich durch
1024 rechnen.

Problem ist der Compiler sagt ich muss einen Math Library
linken, ich weiss aber nicht mehr wie das geht.
Hab bei include schon math.h 68881.h usw. abgegeben.

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 11:46 Uhr

akl
Posts: 265
Nutzer
@MaikG:
Du kannst die Funktion UMult64() aus der utility.library verwenden, müsstest Dir dann aber unter SAS/C per getreg() die oberen 32 Bit holen, also sowas in der Art:

ULONG result[2];

result[1] = UMult64(numblocks, blocksize);
result[0] = getreg(1);

In result[0] kannst Du die GBs oberhalb 4 GB ablesen und aus result[1] die restlichen MB/KB berechnen.

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 11:51 Uhr

MaikG
Posts: 5172
Nutzer
>Das kommt ohne 64 Bit Arithmetik aus, hat allerdings einen Überlauf bei Größen ab 2147483647,5 kB also 2048 GB großen Partitionen.

Cool, das geht bis 2048 GB ist okay.
Prozent hat sich damit schon automatisch gefixt...
Danke!


>Du kannst die Funktion UMult64() aus der utility.library verwenden, müsstest Dir dann aber unter SAS/C per getreg() die oberen 32 Bit holen, also sowas in der Art:

klingt auch nicht schlecht muss ich mir mal merken.

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 11:52 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von MaikG:
Das mit Prozent klingt schon ganz gut, aber muss das nicht
ULONG heissen?

Wie Du willst. Sollte das gleiche ergeben...
Zitat:
Okay, ich hab jetzt mal folgendes gemacht, das Ergebniss
von (totalbytes/1024)*BlocksperTrack in einer Double - die
kann ja 8 Byte erfassen.
Dann eine fallunterscheidung, je nachdem ob es einen Overflow
gibt oder nicht die Normale Routine oder ebend gleich durch
1024 rechnen.

Das ist aber totaler Quatsch. Bei double gibt's keinen Overflow, sondern allenfalls Rundungsfehler. Und wie gesagt, rechne keine übergroßen Produkte aus, die Du danach wieder durch die gleichen Beträge dividieren musst. Dann kannst Du Dir das alles sparen. Übrigens wüsste ich jetzt nicht, was bei (totalbytes/1024)*BlocksperTrack sinnvolles herauskommen soll.
Zitat:
Problem ist der Compiler sagt ich muss einen Math Library
linken, ich weiss aber nicht mehr wie das geht.
Hab bei include schon math.h 68881.h usw. abgegeben.

-lm (in der Kommandozeile)
Aber lass einfach den Quatsch mit der double-Zahl weg, und spar Dir das.

mfg

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 11:57 Uhr

thomas
Posts: 7717
Nutzer
@MaikG:

Mach's doch nicht so kompliziert.

code:
blocks_per_mb = 1024*1024 / BytesPerBlock;
disk_size = NumBlocks / blocks_per_mb; /* size in mb */

if (disk_size < 1024) /* disk is smaller than 1GB */
{
   disk_size = NumBlocks * BytesPerBlock / 1024; /* size in kb */
   used_kb = NumBlocksUsed * BytesPerBlock / 1024;
   free_kb = disk_size - used_kb;
   used_percent = used_kb * 100 / disk_size;
   free_percent = free_kb * 100 / disk_size;
}
else
{
   disk_size *= 1024; /* mb -> kb */
   used_kb = NumBlocksUsed / blocks_per_mb * 1024;
   free_kb = disk_size - used_kb;
   used_percent = used_kb / (disk_size / 100);
   free_percent = free_kb / (disk_size / 100);
}


Gruß Thomas

--
Email: thomas-rapp@web.de
Home: thomasrapp.homepage.t-online.de/

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 12:11 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von thomas:
@MaikG:

Mach's doch nicht so kompliziert.

code:
...
   used_kb = NumBlocksUsed / blocks_per_mb * 1024;


Wer sagt, dass die Partition voll sein muss? Da lässt Du aber ganz schöne Rundungsfehler zu. Wenn die Präzision man gerade für MB reicht, sollte man auch keine Zahlen in kB ausspucken.
Zitat:
code:
used_percent = used_kb / (disk_size / 100);
free_percent = free_kb / (disk_size / 100);


Wo wir schon bei "nicht so kompliziert" sind:
code:
used_percent = used_kb / (disk_size / 100);
free_percent = 100-used_percent;


macht die Sache einfacher und vermeidet durch Rundung verursachte offensichtliche Falschanzeigen, deren Screenshots sich manche User so gerne ins Netz stellen, um sich darüber zu amüsieren.

mfg

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 12:27 Uhr

Holger
Posts: 8116
Nutzer
C code:
ULONG valueIsMB=0, used, max;
if (lock=Lock(file,SHARED_LOCK)) {
  if (Info(lock,idata)) {
    ULONG largest=~0;
    used=idata->id_NumBlocksUsed, max=idata->id_NumBlocks;
    percent=(largest/100 < used)? // potential overflow
      used/(max/100): used*100/max;
    switch(idata->id_BytesPerBlock) {
      ULONG blockFactor; // half kB
      case 512: // mostly used
        used>>=1; // num/2
        max>>=1;
	break;
      case 1024: break;// not so common, but easy to optimize
      default:
        blockFactor=idata->id_BytesPerBlock>>9;
	if(largest/blockfactor < used)
	{
          used=(used*blockFactor)>>1;
          max=(max*blockFactor)>>1;
	}
	else
	{
	  ULONG blockPerMB=(1<<20)/idata->id_BytesPerBlock;
          valueIsMB=1;
          used/=blocksPerMB;
          max/=blocksPerMB;
	}
    }
    ret=1;
  }
  UnLock(lock);
  if(valueIsMB)
    printf("used %d MB, total %d MB, %d %%n", used, max, percent);
  else
    printf("used %d kB, total %d kB, %d %%n", used, max, percent);
}


Da müsste jetzt alles drin sein...

mfg

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 15:03 Uhr

Der_Wanderer
Posts: 1229
Nutzer
Wobfür wurden denn Floats erfunden ?
Rechne doch alles in Float oder Double aus.
Am Ende kannst du es auf MB scalieren.

--
Thilo Köhler, Author von:
HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, TK AB3 Includes und viele mehr...
Homepage: http://www.hd-rec.de


[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 15:13 Uhr

Der_Wanderer
Posts: 1229
Nutzer
Hier ein Beispiel (Amiblitz3/dos.include):

code:
;///////////////////////////////////////////////////////////////////////////////
;/                                                                             /
;/ Syntax:  result.w = dos_CheckDiskSpace {disk.s,bytes.f}                     /
;/                                                                             /
;/ Description:                                                                /
;/ Check if there is bytes.f amount of memory on the given disk path availab:: /
;/ le.                                                                         /
;/ Note: "bytes.f" is a float value, and is allowed to be greater than 2GB.    /
;/                                                                             /
;/ Inputs:                                                                     /
;/ - disk.s   : name of a disk or directory, e.g. "Sys:" or "Sys:T"            /
;/ - bytes.f  : number of bytes                                                /
;/                                                                             /
;/ Result:                                                                     /
;/ - result.w     : -1 if the memory is available, 0 if not                    /
;/                                                                             /
;///////////////////////////////////////////////////////////////////////////////
Function.w dos_CheckDiskSpace {disk.s,bytes.f}
succ.w = False
lock.l=Lock_(&disk.s,#ACCESS_READ)
If lock
  DEFTYPE .InfoData idat
  If Info_(lock, idat)
    If idatid_DiskState = #ID_VALIDATED
      nbu.f = idatid_NumBlocksUsed
      nb.f  = idatid_NumBlocks
      bpb.f = idatid_BytesPerBlock
      bytes_total.f = nb  * bpb
      bytes_used.f  = nbu * bpb
      bytes_free.f  = bytes_total - bytes_used
      If bytes_free>bytes Then succ = True
    End If
  End If
  UnLock_ lock
EndIf
Function Return succ
End Function

--
Thilo Köhler, Author von:
HD-Rec, Sweeper, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, AudioConverter, ScreenCam, PerlinFX, MapEdit, TK AB3 Includes und viele mehr...
Homepage: http://www.hd-rec.de


[ - Antworten - Zitieren - Direktlink - ]

15.08.2007, 18:29 Uhr

MaikG
Posts: 5172
Nutzer
Funktioniert doch schon, musste nur bei prozent für disketten
nochmal eine fallunterscheidung machen...

[ - Antworten - Zitieren - Direktlink - ]


-1- [ - Beitrag schreiben - ]


amiga-news.de Forum > Programmierung > Partionsgröße in 64 Bit [ - Suche - Neue Beiträge - Registrieren - Login - ]


.
Impressum | Datenschutzerklärung | Netiquette | Werbung | Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten.
.