Umwandeln von Zahlen in verschiedene Zahlensysteme mit C



  • Das kommt davon wenn man sich von irgendwoher, irgendwelchen Quellcode per C+P ( Copy & Paste ) besorgt und dann per Reverseengeneering versucht den zu kapieren. 👎

    Also ich würd sagen, daß das nicht schadet.

    In dem Sinn noch zwei Beispiele aus dem Internet (ungetestet):
    http://www.openmash.org/lxr/source/compat/strtoul.c?c=tcl8.3
    http://doxygen.postgresql.org/strtoul_8c-source.html



  • _matze schrieb:

    Hier habe ich auch mal schnell eine Lösung (mal ohne Modulo) gebastelt und gut kommentiert. Vielleicht kommst du damit eher klar.

    #include <stdio.h> 
    #include <stdlib.h> 
    #include <iostream.h>
    #include <string.h> 
    #include <math.h>
    #include <crtdbg.h>
    
    void transformNumber(__int64 number,char *outString,int sys);
    
    int main() { 
      __int64 number=0xAffeAffe;  //Zahl, die es umzuwandeln gilt
      int sys=16;                 //Stellenwertsystem
      char result[128]={0};       //Ergebnis-String
    
      transformNumber(number,result,sys); //Funktionsaufruf
      printf("%s",result);    //Ergebnis ausgeben
      getch();                //Return zum Beenden drücken
    
      return 0;
    }
    
    void transformNumber(__int64 num,char *outString,int sys) {
      int i=0;
      __int64 x=0,exp;
      int count,stringIndex=0;
      for(exp=-1;x<=num;) {  //ermittelt die Anzahl der Stellen (den höchsten Exponenten)
        x=(__int64)pow(sys,++exp);
      }
      exp--;  //Anzahl der nötigen Stellen
      for(i=exp;i>=0;i--) {
        count=0;
        while(num>0) {
          num-=pow(sys,i);    //höchste Potenz einmal abziehen
          if(num<0) {         //wenn num<0, war das zuviel, also...
            num+=pow(sys,i);  //..wieder aufaddieren
            break;
          }else {
            count++;          //Anzahl in dieser Stelle inkrementieren
          }
        }    //String füllen mit Ziffern bzw. ab Anzahl 10 mit Buchstaben
        outString[stringIndex++]=count<10 ? count+48 : count+65-10;
      }
    }
    

    OMG! eindeutig zu kompliziert^^
    es geht doch viel einfacher:

    #include <stdio.h>
    
    // base darf sein 2...36
    void transform (unsigned long v, int base)
    {
      unsigned long z;
      if (z = v/base)  // ja, das ist eine zuweisung
        transform (z, base);
      putchar ("0123456789abcdefghijklmnopqrstuvwxyz"[v-base*z]);
    }
    
    int main() 
    {
      transform (1234, 2);  // als bin
      putchar ('\n');
      transform (1234, 10); // als dezimal
      putchar ('\n');
      transform (1234, 16); // als hex
      putchar ('\n');
      transform (1234, 30); // base 30 
      putchar ('\n');
    }
    


  • Kann mir den niemand erklären wie diese Rechnung zu verstehen ist? Ich versuche das ganze auf dem Papier nachzuvollziehen komme aber leider auf kein brauchbares Ergebnis...
    Vielen dank für die alternativen Quellcodes, allerdings sind mir die noch weniger verständlich. 🙄

    Mfg
    w0lver!ne



  • Zum Thema Verständnis ist das Beispiel von transformatoren-freak wohl das klarste. Was ist dir daran unklar?



  • Beispiel:

    //n ist Zahl, die umgewandelt werden soll (als Beispiel: 35)
    //a ist 1 (als Beispiel: 1)
    //sys2 ist die Basis (als Beispiel: 16)
    
    while (n >= a) 
      a *= sys2;
    
    //a ist immer ein Vielfaches der Basis. Der Exponent wird jede Runde erhöht 
    //(sys2^0, sys2^1, ...). Irgendwann ist a größer als n, der Exponent ist also 
    //um eins zu groß.
    
    //a=1   (<35)
    //a=16  (<35)
    //a=256 (>35!)
    
    // berechnet alle Stellen von der groessten zur kleinsten
            while (a != 1)
                {
                    a /= sys2;
    
                    b = n / a;
                    n %= a;
                    printf("%c", c[b]);
                 }
    
    //Dann wird der Prozess quasi umgekehrt. Man will a wieder auf 1 kriegen, die 
    //Multiplikationen mit sys2 werden wieder rückgängig gemacht.
    
    //256/16  =16  //Diese Stelle (16^1)
    //35/16   =2  //hat diese Anzahl (2).
    //3 MOD 16=3  //Dieser Rest wird beim nächsten Schleifendurchlauf durchprozessiert
    
    //Nächster Durchlauf:
    
    //16/16  =1  //Diese Stelle (16^0)
    //3/1    =3  //hat diese Anzahl (3)
    //3 MOD 1=0  //kein Rest
    
    //Ergebnis 2*16^1 + 3*16^0 = 0x23 !!
    

    Na, war das verständlich? 😉



  • Ja, danke vielmals...das war sehr verständlich!

    Mfg
    w0lver!ne



  • w0lver!ne schrieb:

    Kann mir den niemand erklären wie diese Rechnung zu verstehen ist? Ich versuche das ganze auf dem Papier nachzuvollziehen komme aber leider auf kein brauchbares Ergebnis...
    ... 🙄

    Mfg
    w0lver!ne

    Meinst du transformatoren-freaks Beispiel ?
    Dazu müsstest du dir angucken, wie rekursive Funktionen arbeiten und wie die Parameter auf dem Stack zwischengelagert werden.
    Vielleicht hat ja auch trafofreak Lust es dir zu erklären.

    Ich will mit meiner Lösung auch nicht geizen^^

    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    
    // Return values,
    // 1: error, 0: ok
    int convert( unsigned num, unsigned radix, char* resbuf, unsigned size )
    {
      int n = 0, r = 0, i = 0;
    
      if ( radix > 36 )
      {
    	errno = EINVAL; // Ungültiger Parameter, Basis zu groß.
    	return 1;
      }
    
      while ( num >  0 )
      {
    	  n = num / radix;
    	  if ( ( r = (num - n*radix) ) > 9 )
    		  resbuf[i] = r + 55;
    	  else 
    		  resbuf[i] = r + 48;
    	  i++;
    	  num = n;
    
    	  if( i > ( size -1 ) )
    	  {
    		errno = ERANGE; // Puffer zu klein.
    		return 1;
    	  }
      }
    
      resbuf[i] = 0;
    
      r = strlen(resbuf);
      n = r-1;
    // Das Ergebnis liegt in umgekehrter Reihenfolge im Speicher.	
      for ( i=0; i<r/2; i++, n-- )
      {
    	  num = resbuf[i];
    	  resbuf[i] = resbuf[n];
    	  resbuf[n] = num;
      }
    
      return 0;
    }
    
    int main()
    {  
    	int num = 123456789, radix = 8;
    	char result[64];
    
    	if ( convert( num, radix, result, sizeof(result) ) )
    		return 1;
    	puts(result);
    
    	return 0;
    }
    


  • Big Brother schrieb:

    Vielleicht hat ja auch trafofreak Lust es dir zu erklären.

    ist im prinzip ganz einfach.
    der wert wird durch die basis geteilt und das ergebnis wieder und wieder usw..., bis nichts mehr übrig bleibt.
    weil's eine integer-division ist, bleibt fast immer ein rest (0...base-1). dieser rest wird als index in ein ziffern-array benutzt und die entsprechende ziffer wird ausgegeben. das kannste z.b. schriftlich prima nachrechnen
    wäre die funktion nicht-rekursiv, dann würde die zahl in umgekehrter reihenfolge erscheinen. durch die rekursion wir die ausgabe zurückgehalten, d.h. erst nachdem die letzte berechnung gemacht wurde, werden alle rekursionen zurückgespult und geben nacheinander ihre ziffern aus, wobei die tiefste rekursion als erstes dran kommt usw.

    hier mal eine nicht-rekursive variante, die die ziffern umgekehrt in ein array schreibt:

    char* transform (unsigned long v, int base)
    {
      static char res[256];
      char *p = res;
      while (v)
      {
        unsigned long z = v/base;
        *--p = "0123456789abcdefghijklmnopqrstuvwxyz"[v-base*z];
        v = z; 
      }
      return p;
    }
    
    int main()
    {
      puts (transform (1234, 2));  // als bin
      puts (transform (1234, 10)); // als dezimal
      puts (transform (1234, 16)); // als hex
      puts (transform (1234, 30)); // base 30
    }
    

    🙂



  • rekursions-freak schrieb:

    "0123456789abcdefghijklmnopqrstuvwxyz"[v-base*z];
    

    Die Schreibweise kannte ich noch gar nicht, gefällt mir ja irgendwie.^^



  • Big Brother schrieb:

    rekursions-freak schrieb:

    "0123456789abcdefghijklmnopqrstuvwxyz"[v-base*z];
    

    Die Schreibweise kannte ich noch gar nicht, gefällt mir ja irgendwie.^^

    wenn du die leute völlig verwirren willst, dann schreib es so:

    *--p = (v-base*z)["0123456789abcdefghijklmnopqrstuvwxyz"];
    

    🙂


Anmelden zum Antworten