Funktionales C++



  • Guten Abend,

    an der Uni sollen wir momentan C++ nicht voll ausnutzen (Konsolenanwendungen). Stattdessen sollen wir ne Art C++-light benutzen, auch funktionales C++ genannt. Hier sind nur wenige Dinge erlaubt, unter anderem dürfen keine if-Verzweigungen oder Schleifen verwendet werden. Anstatt einer if-Anweisung dürfen wir nur den Auswahloperator verwenden, also sowas hier:

    (n==0) ? n : -n

    Des Weiteren sind im C++-light keine Zuweisungen erlaubt, dafür aber Funktionsaufrufe.

    Und die Aufgabe, die wir jetzt grad machen sollen ist eine schnelle Potenzierung. Wenn ich C++ "normal" verwende, dann komm ich auf diesen Algorithmus:

    #include <stdio.h>
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    double expon(double x, int n) {
        if(n == 0) {
            return 1.0;
        } else if(n % 2 == 0) {
            return expon(x * x, n / 2);
        } else {
            return x * expon(x * x, (n - 1) / 2);
        }
    }
    
    int main() {
    	cout << expon(4,4);
    	cin.get();
    	return 0;
    }
    

    Der funktioniert auch. Aber jetzt muss ich das ganze ja in C++-light umwandeln, d.h. einen Algorithmus entwickeln, bei dem ich auf Zuweisungen verzichte, stattdessen nur mit diesem Auswahloperator und mit Funktionsaufrufen arbeite. Dann hab ich das mal so probiert:

    #include <stdio.h>
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    double expon2(double x, int n) {
        return (n%2==0) ? (expon2(x*x, n/2)):(x*expon2(x*x, (n-1)/2));
    	return 0;
    }
    
    double expon(double x, int n) {
    	return (n==0) ? 1:expon2(x,n);
    }
    
    int main() {
    	cout << expon(4,4);
    	cin.get();
    	return 0;
    }
    

    Das funktioniert aber auch nicht, da immer die Meldung "stackoverflow" kommt. Dummerweise kann man den Auswahloperator nicht schachteln. Also hab ich eben versucht, von der Funktion expon die Funktion expon2 aufzurufen. Aber dann hab ich das overflow-Problem. Wüsste jemand ne Lösung bzw. kann mir jemand Hinweise geben, wie ich das lösen kann? Bin für jeden Tipp dankbar!


  • Mod

    Von expon2 aus wird bei dir immer nur expon2 aufgerufen, daher kommst du nie zu der abbruchbedingung die in expon steht.

    P.S.: Den Auswahloperator kann man nicht schachteln? Komisch, muss ich gleich mal selber ausprobieren...

    edit: Ausprobiert. Den kann man wohl schachteln, wäre ja auch zu komisch, wenn man es nicht könnte. Hast du vielleicht einfach nur die Syntax falsch? Achte auf die richtige Klammerung!



  • SeppJ schrieb:

    P.S.: Den Auswahloperator kann man nicht schachteln?

    Doch, natürlich. In C++ sind Operatoren ja nur Funktionen, die einen Ausdruck zurückgeben, der dann seinerseits in einem sinnvollen Kontext verwendet werden kann (z.B. wiederum als Operatorargument). Der operator?: ist zwar etwas speziell, aber grundsätzlich trifft diese Überlegung zu.

    Ob es in "C++-Light" diesbezüglich Einschränkungen gibt, weiss ich allerdings nicht.



  • Die Lösung steht doch schon fast da:

    double expon(double x, int n) {
        return n == 0 
          ? 1.0 
          : n % 2 == 0 
            ? expon(x*x, n/2)
            : x * expon(x*x, (n-1)/2);
    }
    

    (Achja, selbstverständlich kann man den ternären Operator schachteln.)



  • Erstmal danke für eure schnellen Antworten 🙂

    Hmm, also ich hab heute Mittag den Operator geschachtelt, aber da kamen ständig Fehlermeldungen. Muss ich gleich nochmal ausprobieren. Ich melde mich wieder.



  • Also, manchmal gehör ich doch geschlagen 🙄 Hatte das heute Mittag so geschrieben:

    return (n == 0) ? 1.0 : return (n % 2 == 0) ? expon(x * x, n / 2) : x * expon(x * x, (n - 1) / 2);
    

    Da hatte ich einfach ein Return zuviel eingebaut. Jetzt wenn ichs wegmache, geht alles einwandfrei. Und ich hab schon gedacht, diesen Operator könne man einfach nicht schachteln.

    Nochmal sorry....da war ich mal wieder dabbich 🕶

    Danke für eure Hilfe!



  • Hallo, ich bins schon wieder 😞

    Ich hab ein neues Problem mit meinem neuen Programm. Und zwar schließt sich die Konsole ständig bevor ich ne Ausgabe bekomme. Ich habs schon mit cin.get() probiert, aber egal wo und egal wie oft ich das hinschreib, die Konsole schließt sich noch ehe ich die Ausgabe betrachten kann.

    #include <stdio.h>
    #include <iostream>
    #include <cmath>
    //#include <conio.h>
    using namespace std;
    
    int potenz(int x, int n) {
    	return (n == 0) ? 1 : (n % 2 == 0) ? potenz(x * x, n / 2) : x * potenz(x * x, (n - 1) / 2);
    }
    
    void wrong() {
    	cout << "Falsche Eingabe! Bitte nochmal versuchen.";
    }
    
    int main() {
    	int a,b;
    	cout << "Geben Sie eine natuerliche Zahl x>=1 ein: "; 
    	cin >> a;
    	cout << "Geben Sie eine natuerliche Zahl n>=1 ein: ";
    	cin >> b;
    	return (a<1) ? wrong() : ((b<1) ? wrong() : potenz(a, b));
    	cin.get();
    	return 0;
    }
    

    mit getch() hab ichs auch schon probiert. Ohne Erfolg. Wie krieg ich das hin, dass diese Konsole offen bleibt?


  • Mod

    Das liegt daran, dass du ein return vor dem get hast. Bei return aus main wird das Programm beendet, es kommt gar nicht zu dem get.

    Sollte eigentlich eine Compilerwarnung geben, zumindest wenn du einstellst, dass der Compiler etwas pingeliger sein soll.



  • Danke erstmal für die Antwort. Wie kann ich trotz dem return verhindern, dass die Konsole sich schließt? Das Return brauch ich leider, da ich keine if-Anweisungen verwenden darf.



  • Ich hätte es beinahe übersehen
    return (a<1) ? wrong() : ((b<1) ? wrong() : potenz(a, b));
    (return verlässt die Fkt sofort)
    du willst hier vermutlich nur eine Ausgabe

    nimm bitte nächstes mal die C++ tags und nicht die Code Tags

    Ach so:
    #include <stdio.h>
    ist deprecated, so sollte es heißen:
    #include <cstdio>

    wenn du einen ordentlichen compiler hast, sagt der dir auch "unreachable code" nach deinem return und so hättest du es selbst gemerkt^^

    bb

    edit: viel zu langsam ><
    du brauchst dort kein return - das ist noch dazu falsch, weil wrong auch nichts zurückgibt... -> undefiniertes verhalten



  • Mein Compiler ist Visual C++. Der scheint ziemlich gutmütig zu sein^^

    Also mein Programm soll einfach folgendes können:

    - 2 Zahlen sollen vom Benutzer eingegeben und diese dann als Parameter an potenz() übergeben werden. In der Funktion potenz() soll dann die Potenz zurückgegeben werden. Allerdings soll vorher geprüft werden, ob die Eingaben von x und n korrekt waren. x und n sollen größer gleich 1 sein. Ich darf halt keine Zuweisungen und if-Anweisungen verwenden. Und da liegt mein Problem. Als if-Alternative darf ich also nur den Auswahloperator nehmen, muss also mit

    return (irgendwas) ? dies : jenes

    arbeiten. Gleichzeitig soll ich aber auch auf dem Bildschirm die Rechnung ausgeben. Ich kann ja nicht cout in nem Return-statement benutzen. Hab ehrlich gesagt keine Ahnung, wie ich das machen soll, dass der mir die Eingaben prüft und dann noch die Rechnung ausgibt (und dann noch die Konsole offen hält).



  • Wieso lässt der Compiler das überhaupt durch? Die Ergebnisse der beiden Zweige des ?: müssten dachte ich den gleichen Typ haben?!

    Und wegen der Rückgabe, ich glaube der Standard schreibt nicht vor dass das Betriebssystem als Returnwert den kompletten Wertebereich eines int auswerten muss. Irgendwie fehlt da jegliche Ausgabe.



  • Lass return weg und schick das Ergebnis der Berechnung nach cout. Dann hast Du immernoch keine ifs.

    Und wrong sollte vielleicht 0 oder sowas zurückgeben, da sonst eben gesagtes gilt.



  • LordJaxom schrieb:

    Lass return weg und schick das Ergebnis der Berechnung nach cout. Dann hast Du immernoch keine ifs.

    Und wrong sollte vielleicht 0 oder sowas zurückgeben, da sonst eben gesagtes gilt.

    Ich darf return leider nicht wegmachen, weil in der Aufgabe steht, dass ich eine Funktion "int potenz(int x, int n)" erstellen soll. 😞 Wenn die mich doch nur das normale C++ benutzen lassen würden. Aber wir sollen ja dummerweise dieses abgespeckte C++ nehmen



  • Wir sprechen von dem return in main. Dass die Funktion etwas zurückgeben muss, ist logisch.



  • LordJaxom schrieb:

    Wieso lässt der Compiler das überhaupt durch? Die Ergebnisse der beiden Zweige des ?: müssten dachte ich den gleichen Typ haben?!

    Jopp - der MSVC compiliert es auch nicht...

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    
    using namespace std;
    
    int potenz(int x, int n)
    {
        return (n == 0)
    		? 1
    		: (n % 2 == 0)
    			? potenz(x * x, n / 2)
    			: x * potenz(x * x, (n - 1) / 2);
    }
    
    void wait()
    {
    	cin.clear();
    	cin.ignore( cin.rdbuf()->in_avail() );
        cin.get();
    }
    
    const char* wrong = "Falsche Eingabe! Bitte nochmal versuchen.";
    
    int main()
    {
        int a,b;
        cout << "Geben Sie eine natuerliche Zahl x>=1 ein: "; 
        cin >> a;
        cout << "Geben Sie eine natuerliche Zahl n>=1 ein: ";
        cin >> b;
    	cout << ((a<1 || b<0) ? wrong : "potenz(a, b)") << endl;
    
    	wait();
    }
    

    geht wunderbar

    wenn man nun allerdings nicht "potenz(a, b)" sondern potenz(a, b) ausgeben möchte, geht das mit dem ternären operator wirklich nicht^^

    bb

    edit:
    so geht es aber

    int main()
    {
        int a,b;
    	cout << "Geben Sie eine natuerliche Zahl x>=1 ein: "; 
    	cin >> a;
    	cout << "Geben Sie eine natuerliche Zahl n>=1 ein: ";
    	cin >> b;
    	a<1 || b<0 ? cout << wrong : cout << potenz(a, b);
    	cout << endl;
    
    	wait();
    }
    

    allerdings würd ich noch paar klammern reinmachen, weil sonst ja gar niemand mehr durchsieht 😉



  • Ok, danke! So gehts wirklich. Meine Güte....ist aber umständlich. 🙄



  • Euler schrieb:

    Ok, danke! So gehts wirklich. Meine Güte....ist aber umständlich. 🙄

    ist jede sprache, wenn man sie ganz anders verwendet als es deren paradigmen eigtl vorschreiben - wenn es überhaupt geht...



  • unskilled schrieb:

    Euler schrieb:

    Ok, danke! So gehts wirklich. Meine Güte....ist aber umständlich. 🙄

    ist jede sprache, wenn man sie ganz anders verwendet als es deren paradigmen eigtl vorschreiben - wenn es überhaupt geht...

    Ich verstehs ja auch nicht, warum wir das machen müssen. Gott sei Dank wird das in ein paar Wochen aufhören. Es bringt ja nichts wenn wir C++ lernen sollen und es dann einfach nicht voll ausnutzen dürfen. Schon gar nicht, wenn man schon die einfachsten Anweisungen ignorieren soll.

    Ein Programm ohne Zuweisungen 🙄



  • naja, das es nichts bringt, würde ich nicht sagen

    ist imho ein schönes bsp., wie funktionale sprachen funktionieren
    und man muss als lehrer/dozent seine zeit nicht mit 2mal syntax lehren verschwenden
    soll nicht heißen, dass es die tollste methode ist, aber als grundverkehrt würd ich sie auch nicht gleich einschätzen...

    bb


Log in to reply