Umwandeln von Zahlen in verschiedene Zahlensysteme mit C



  • Ein Kollege hat mir folgendes geschrieben:

    void umrechnen (int sys, long int Zahl)
    {
    if (Zahl > 0)
    {
    short Zahl2 = Zahl % sys;
    umrechnen(sys, Zahl/sys);
    if (Zahl2 < 10)
    printf("%d", Zahl2);
    else
    printf("%C", (55+Zahl2))
    

    Allerdings verstehe ich jetzt den letzten Ausdruck mit in Zeile 10 nicht so recht in seiner Bedeutung und Wirkung. Mir würde es schon sehr helfen wenn mir jemand den erklärt.
    Der Ausdruck in Zeile 7-8 bewirkt doch das Zahlen > 10 wie im HEX mit A-F benannt werden, oder?
    Ich bin in der Programmierung neu und habe diese nette Aufgabe als Ausarbeitung auferlegt bekommen allerdings lies der Unterricht zu wünschen übrig. 😞

    Mfg
    w0lver!ne



  • Hi !
    Die Summe 55+Zahl2 ist für Zahl2 > 9 eine Umrechnung, um den Ascii-Code des gewünschten Buchstabens zu bekommen:

    Zeichen        Ascii-Code
    
    '7'            55
    '8'            56
    '9'            57
    
    'A'            65
    'B'            66
    


  • man: strtoul und Freunde nehmen btw einen Parameter für die System-Basis. Geht wahrscheinlich auch andersrum.



  • Hi, wir haben nun einen laufenden Quellcode.
    Nun geht es daran das ganze auch Sinnvoll erklären zu können.
    Würde mich freuen wenn ich auch hier Fachmännische Hilfe von euch bekommen würde.

    // sucht die erste Potenz von sys2 die grosesser als n ist
    		while (n >= a)
    		a *= sys2;
    
    // berechnet alle Stellen von der groessten zur kleinsten
    		while (a != 1)
    			{
    				a /= sys2;
    
    // berechnet die aktuelle Stelle
    				b = n / a;
    				n %= a;
    				printf("%c", c[b]);
    
    // sucht die erste Potenz von sys2 die grosesser als n ist
    		while (n >= a)
    		a *= sys2;
    

    Ich nehme an das damit bestimmt wird wieviele stellen für die Darstellung der umgerechneten Zahl benötigt wird.
    Bitte korrigiert mich wenn ich falsch liege!

    // berechnet alle Stellen von der groessten zur kleinsten
    		while (a != 1)
    			{
    				a /= sys2;
    
    // berechnet die aktuelle Stelle
    				b = n / a;
    				n %= a;
    				printf("%c", c[b]);
    			}
    

    Hier verstehe ich teils nicht was damit bezweckt wird und würde mich freuen wenn mir den jemand erklärt.
    Der untere Teil der Division und Modulo Operation ist soweit auch klar aber was geschieht im oberen Teil?

    Vielen dank ersteinmal.

    Mfg
    w0lver!ne



  • w0lver!ne schrieb:

    Hi, wir haben nun einen laufenden Quellcode.
    Nun geht es daran das ganze auch Sinnvoll erklären zu können.
    Würde mich freuen wenn ich auch hier Fachmännische Hilfe von euch bekommen würde.

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

    👎



  • 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;
      }
    }
    

    EDIT: Und falls deine Verständnisschwierigkeiten bei "deinem" Code daher rühren, dass du die Operatoren nicht kennst, ein kleiner Tipp:

    a+=b;  /*ist äquivalent zu*/  a=a+b;
    a*=b;  /*ist äquivalent zu*/  a=a*b;
    /*usw.*/
    


  • Kenner der C+P NOOBs schrieb:

    w0lver!ne schrieb:

    Hi, wir haben nun einen laufenden Quellcode.
    Nun geht es daran das ganze auch Sinnvoll erklären zu können.
    Würde mich freuen wenn ich auch hier Fachmännische Hilfe von euch bekommen würde.

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

    👎

    Ich bin auch kein Fan davon...ich bin nur leider nicht in der Lage zu programmieren da ich die Befehle nicht kenne...Und in den Übungen ist nichtmals ansatzweise ausreichend darauf eingegangen worden ist.
    Der mathematische weg ist simpel, das ganze ins Programm zu bringen ist aber was anderes.

    Mfg
    w0lver!ne



  • 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