Zwei Probleme :D Einmal String in (duodecimal) int umwandeln und int in Binärdarstellung mittels Bitmaske?



  • Moin 🙂

    Ich habe zwei Probleme, die ich alleine nicht ganz gelöst bekomme 😃 Wir hatten Aufgaben, die ich so weit es ging gelöst hatte,wobei bei der einen ich übersehen habe das POW (also aus der Mathe Bibliothek) gar nicht erlaubt war und ich auch gar nicht weiß wie man es ohne lösen würde.

    Denn wenn ich eine Duodecimal Zahl in eine Dezimal Zahl umwandeln will nehme ich immer die jeweilige Zahl und multipliziere sie mit je nach dem einer Potenz von 12 und addiere sie mit den anderen. In Code sieht das folgendermaßen aus:

    int str_to_int(char *duo_zahl, int length)
    {
    
    	int i, zahl = 0;
    	for(i=0; i<= length-1; i++)
    	{
    		switch(duo_zahl[((length-1)-i)])
    		{
    		case '0': zahl+= 0*(pow(12,i)); break;
    		case '1': zahl+= 1*(pow(12,i)); break;
    		case '2': zahl+= 2*(pow(12,i)); break;
    		case '3': zahl+= 3*(pow(12,i)); break;
    		case '4': zahl+= 4*(pow(12,i)); break;
    		case '5': zahl+= 5*(pow(12,i)); break;
    		case '6': zahl+= 6*(pow(12,i)); break;
    		case '7': zahl+= 7*(pow(12,i)); break;
    		case '8': zahl+= 8*(pow(12,i)); break;
    		case '9': zahl+= 9*(pow(12,i)); break;
    		case 'y': zahl+= 10*(pow(12,i)); break;
    		case 'Y': zahl+= 10*(pow(12,i)); break;
    		case 'z': zahl+= 11*(pow(12,i)); break;
    		case 'Z': zahl+= 11*(pow(12,i)); break;
    		case '+': zahl=zahl; break;
    		case '-': zahl=-zahl; break;
    		}	
    
    	}
    
    	return zahl;
    
    }
    

    Das soll ich jetzt aber OHNE pow Funktion hinkriegen, könnt ihr mir erklären wie ich das hinbekomme?? 😞

    Und zum zweiten, nachdem man in dem Prog rumgespielt hat soll man noch Integer in Binärdarstellung anzeigen lassen. Der Prof hat gesagt man muss nur eine For Schleife laufen lassen, eine Bitmaske auf den Integer (also in dem Fall int ergebnis also je nach dem was für eine Zahl kommt) und dann über die Bitmaske auf die 1en und 0en kommen... Wichtig ist das man immer einen weitergeht, anscheinend hat er das im ersten Semester erwähnt und seine Vorlesung habe ich gar nicht besucht 😃 Im Internet bin ich jetzt nicht wirklich schlau drauß geworden.

    Also denken kann ich mir schon irgendwie For Schleife die bis 32 geht, dann muss irgendwie/irgendwo ein Index mit drin sein der dann eben inkrementiert wird damit man ein Bit weitergeht, aber weiß jetzt nicht ganz genau von Syntax wie ich das hinschreiben soll 😕

    Ich hoffe es findet sich noch heute jemand der mir ein klein wenig Klarheit verschaffen kann 😞



  • Pseudocode:

    int str_to_int(char *str, int length) 
    { 
    	num = 0;
    	für jeden char c // nicht nur bis length-1, sondern solange i<length !
    	{
    		num *= 12 // zahl um eine stelle verschieben, wir sind im 12er system, also mal 12
    		wenn(c >= '0' && c <= '9') // 0-9 leigen in der ASCII Tabelle hintereinander
    			num += c - '0'
    		wenn(c == 'y' || c == 'Y') // test für nicht ziffern 
    			num += 10
    		wenn(c == 'z' || c == 'Z') // test für nicht ziffern 
    			num += 11
    	}
    	return num
    }
    
    int numDigits(int num)
    {
    	len = 0
    	solange(num != 0)
    	{
    		num /= 2
    		len++
    	}
    	return len
    }
    
    void int_toBinary(char str[33], int num)
    {
    	len = numDigits(num)
    	str[len] = '\0' // terminator
    
    	for(int i = len-1; i>=0; i--) // rückwärts, weil sonst die letzte stelle zuerst eingelesen wird, unser string also verkehrt herum ist
    	{
    		str[i] = num&1 ? '1' : '0' // wenn letzte stelle eine 1, dann '1' sonst '0'
    		num /= 2 // unsere Zahl um eine Stelle nach rechts verschieben
    	}
    }
    


  • Sanj3k schrieb:

    Moin 🙂

    Moin!
    Versuch doch mal, Deine eigene Funktion zu schreiben, statt pow() zu benutzen.

    /* int pow12(int i)
       Gibt den Wert 12 "hoch" i zurueck
    */
    int pow12(int i){
      /* codecodecode */
    }
    

    Das ist doch zu schaffen!



  • Übrigens kannst du dein switch vereinfachen.
    Du nutzt die Tatsache aus, dass die Ziffern im ASCII Code hintereinander stehen.
    Wenn du eine Ziffer als Zeichen hast und davon '0' (erste Ziffer im ASCII Code) abziehst, erhälst du die Nummer.
    Das bedeutet, dass du einfach folgendes schreiben kannst:

    if (isnum(duo_zahl[((length-1)-i)])) // wenn Ziffer
       zahl+=(duo_zahl[((length-1)-i)]-'0')*(pow(12,i));
    


  • Vielen Dank besonders an DarkShadow44 alleine wie ich es mir mit dem Switch Case verschlimmbessert habe obwohl wir beide auf das gleiche Ergebnis kommen und sogar ohne Pow 😃

    @Furble Wurble
    Das wäre auch eine Idee gewesen, einfach mal rein zu gucken in der lib was denn pow macht und sich eine eigene Funktion zu schreiben, wobei ich dachte dass der Prof genau den Weg von DarkShadow haben wollte 🙂


  • Mod

    Sanj3k schrieb:

    Das wäre auch eine Idee gewesen, einfach mal rein zu gucken in der lib was denn pow macht und sich eine eigene Funktion zu schreiben, wobei ich dachte dass der Prof genau den Weg von DarkShadow haben wollte 🙂

    Du wirst es doch wohl hin bekommen, eine Potenz zu berechnen, ohne den Code abschreiben zu müssen?

    Letztlich wird die Implementierung von pow in deiner Standardbibliothek vermutlich ziemlich kompliziert sein, weil diese alle möglichen low-level Tricks ausnutzen wird, um auch noch das letzte an Performance heraus zu kratzen. Aber eine ganz naive Implementierung einer Potzenzfunktion ist selbst für Anfänger sehr leicht und in 4 Zeilen oder weniger machbar. 70 Zeichen maximal.



  • 70 Zeichen maximal.

    Ist das eine absichtliche Codegolf-Vorlage? Edit: Ich schätze nicht.


  • Mod

    Arcoth schrieb:

    70 Zeichen maximal.

    Ist das eine absichtliche Codegolf-Vorlage? Edit: Ich schätze nicht.

    Nein, das war bloß fix an den Fingern abgezählt, wie lang eine ganz naive Implementierung ist, plus ein bisschen Extra, da man als Anfänger vielleicht auch mal foo = foo * 12 statt foo *= 12 schreibt. Ich will's aber nicht vormachen, das soll der Threadersteller mal schön selber machen.

    Wir können natürlich eine Runde Codegolf versuchen, auch wenn das Problem nicht sehr spannend ist. Also Aufgabe:

    int pow12(int i)
    {
      // gibt 12 hoch i zurück
    }
    

    Sprache: C11, freestanding Implementation (also kein pow-Aufruf!). Sind unportable Tricks erlaubt? Ich sag mal ja, da es die Kreativität fördert. Aber ich glaube nicht, dass das Problem viel hergibt:

    return i?12*pow12(i-1):1;
    

    Das sind 25 Zeichen.



  • !i||(pow12(i-1),r*=12);
    

    23 Zeichen, wenn man die Definition der globalen Variable r nicht mitzählt.
    Man braucht kein return-Statement weil unter gccs calling conventions, eax zurückgegeben wird und das enthält die letzte Berechnung, im Fall i == 0, also !i, d.h. 1, ansonsten r*=12, also das gewünschte Ergebnis.


  • Mod

    Nathan schrieb:

    !i||(pow12(i-1),r*=12);
    

    23 Zeichen, wenn man die Definition der globalen Variable r nicht mitzählt.
    Man braucht kein return-Statement weil unter gccs calling conventions, eax zurückgegeben wird und das enthält die letzte Berechnung, im Fall i == 0, also !i, d.h. 1, ansonsten r*=12, also das gewünschte Ergebnis.

    Der Code funktioniert aber nur einmal, außer du setzt r wieder auf 1. Und dann bist du wieder auf > 25 Zeichen.

    edit: Ich habe natürlich nicht spezifiziert, dass die Funktion mehrmals aufrufbar sein soll. Insofern: Cleveres Ausnutzen der Regellücke 👍

    edit2: Eine offensichtliche Verbesserung: !i|| wird zu i&&

    edit3: Ich hatte auch schon an ein Ausnutzen dieser Eigenart des GCC gedacht, wusste aber nicht, dass ein einfacher Ausdruck nicht reicht und daher hat mein Versuch nicht geklappt (Das Ergebnis wurde anscheinend nirgends gespeichert oder der Ausdruck ganz wegoptimiert). Aber mit dieser Vorgabe bekomme ich es richtig hin:

    int pow12(int i)
    {
      i=i?12*pow12(i-1):1;  // 20 Zeichen, ganz ohne Geschummel mit globalen Variablen
    }
    


  • SeppJ schrieb:

    edit2: Eine offensichtliche Verbesserung: !i|| wird zu i&&

    Oh, ja. edit: geht nicht, da sonst 0 in eax und nicht 1.

    edit3: Ich hatte auch schon an ein Ausnutzen dieser Eigenart des GCC gedacht, wusste aber nicht, dass ein einfacher Ausdruck nicht reicht und daher hat mein Versuch nicht geklappt (Das Ergebnis wurde anscheinend nirgends gespeichert oder der Ausdruck ganz wegoptimiert).

    Ja, fiel mir nach dem Posten auch auf, dass man einfach deine Lösung ohne return nehmen könnte.
    Nichtdestotrotz ist meine cooler. Kommaoperator + short circuit ausnutzen.


  • Mod

    Nathan schrieb:

    Ja, fiel mir nach dem Posten auch auf, dass man einfach deine Lösung ohne return nehmen könnte.

    Nein, eben gerade nicht. Ich weiß nicht genau, warum, aber es funktioniert nicht. Ich muss i= davor schreiben, damit es geht.


Log in to reply