Flächeninhalt bestimmen



  • Hallo,

    Ich bin sehr frisch im Programmieren und habe es mit einer Switch Bedingung zu tun. Die Aufgabe ist mit einer Funktion die Art eines Dreiecks nur mit den Seitenlängen herauszufinden. Folgendes habe ich, jedoch wird bei allen Parametern immer null ausgegeben
    Ich freue mich auf Antworten, wo ich einen Fehler habe.
    schönen Abend!

    
    int main (){
    
    
    char  p="1";
    
    
    
      art_von_dreieck(7,7,7);
    p= art_von_dreieck();
    switch(p){
    
    case '1':
        printf("rechtwinkling");
        break;
    case'2':
        printf("gleichschenklig");
        break;
    case '3':
        printf("beliebig");
        break;
        
    default:
        printf("nicht die Seiten eines Dreiecks");
    
    }
    return 0;
    
    }
    
    int art_von_dreieck (int a, int b, int c){
        
        if(a*a+b*b==c*c){
            return 1;
        }
        
        else if (a==b && a!=c){
                 return 2;
        }
        else if (a!=b && a!=c){
             return 3;
        }
        
        }
        
    
    


  • Das kompiliert doch nichtmal so wie du es hier geschrieben hast.



  • @Switch_24 sagte in Flächeninhalt bestimmen:

    Ich freue mich auf Antworten, wo ich einen Fehler habe.


    1. Fehler:
    @Switch_24 sagte in Flächeninhalt bestimmen:

    Folgendes habe ich, jedoch wird bei allen Parametern immer null ausgegeben

    Der von Dir gezeigte Code (wenn er denn kompilieren würde), gibt nirgends "null" (oder 0) aus. ~> Du zeigst nicht den Code, von dem Du sprichst.


    2. Fehler:
    Dein Code kompiliert nicht, kann also garnichts ausgeben. Zeig Code der kompiliert! (Vernünftig eingerückt und als Code formatiert: Schreibe in eine Zeile vor deinen Code ```c und in eine Zeile nach Deinem Code ```. Alternativ markiere Deinen Code, wähle "C" in dem Dropdown in der Toolbar über dem Eingabefenster aus und klicke auf das </> rechts daneben.)


    3. Es fehlt zumindest ein #include und der Prototyp (die Deklaration) von art_von_dreieck() bevor die Funktion verwendet wird.


    4. Fehler:
    @Switch_24 sagte in Flächeninhalt bestimmen:

    char  p="1";
    

    Du versuchst einem character (EIN Zeichen) einen String (eine ZeichenKETTE) zuzuweisen.


    5. Fehler:

    @Switch_24 sagte in Flächeninhalt bestimmen:

    p = art_von_dreieck();
    

    Du versuchst eine Funktion die drei Parameter nimmt mit 0 Parametern aufzurufen. ~>

    p = art_von_dreieck(7,7,7);
    

    6. Fehler:
    1 ist nicht dasselbe wie '1'. Das eine ist eine Zahl (wirklich der Wert 1) und das andere ein Zeichen das durch einen Zahlenwert repräsentiert wird. '1' wird im ASCII zum Beispiel durch 49 (0x31) repräsentiert. Da Deine Funktion die Zahlen 1, 2 oder 3 zurückgibt, dein switch() aber mit den Zeichen '1' (49), '2' (50) und '3' (51) vergleicht ... Warum speicherst Du das Ergebnis Deiner Funktion nicht einfach in einem integer?


    7. Fehler:
    Deine Funktion geht davon aus daß die Schenkel eines gleichschenkeligen Dreiecks immer die Parameter a und b sind. Die Bedingung müsste allgemein eher so aussehen:

    (a == b && a != c || b == c && b != a || c == a && c != b)


    8. Fehler:
    Deine Funktion hat einen Pfad der keinen Wert zurückgibt.

    stmt.return/2:

    [...] Flowing off the end of a constructor, a destructor, or a non-coroutine function with a cv void return type is equivalent to a return with no operand. Otherwise, flowing off the end of a function other than main or a coroutine ([dcl.fct.def.coroutine]) results in undefined behavior.



  • Ja da war es gestern schon spät. Ich meine den den fault Wert als Rückgabe.

    #include <stdio.h>
    #include <stdlib.h>
    
    
    
    
    int main (){
    
    
    char  p='1';
    
    
    
      art_von_dreieck(7,7,7);
    p= art_von_dreieck();
    switch(p){
    
    case '1':
        printf("rechtwinkling");
        break;
    case'2':
        printf("gleichschenklig");
        break;
    case '3':
        printf("beliebig");
        break;
        
    default:
        printf("nicht die Seiten eines Dreiecks");
    
    }
    return 0;
    
    }
    
    int art_von_dreieck (int a, int b, int c){
        
        if(a*a+b*b==c*c){
            return 1;
        }
        
        else if (a == b && a != c || b == c && b != a || c == a && c != b){
                 return 2;
        }
        else if (a!=b && a!=c){
             return 3;
        }
        
        }
        
    
    
        
    
    


  • @Swordfish Zu 5. Fehler. Ist dann also eine Funktion überflüssig?



  • @Switch_24 sagte in Flächeninhalt bestimmen:

    Ich meine den den fault Wert als Rückgabe.

    Ich weiß jetzt nicht was ich sagen soll. Da ist immer noch keine Null.

    @Switch_24 sagte in Flächeninhalt bestimmen:

    Ist dann also eine Funktion überflüssig?

    Das da:

    @Switch_24 sagte in Flächeninhalt bestimmen:

      art_von_dreieck(7,7,7);
    p= art_von_dreieck();
    

    Sind zwei Funktionsaufrufe einer Funktion Namens art_von_dreieck. Einmal rufst Du sie auf und übergibst ihr drei Parameter (7, 7 und 7) und einmal rufst Du sie ohne Parameter auf. ???



  • @Swordfish ok danke, das mit der Funktion habe ich geändert



  • @Swordfish

    @Switch_24 sagte in Flächeninhalt bestimmen:

      art_von_dreieck(7,7,7);
    p= art_von_dreieck();
    

    Sind zwei Funktionsaufrufe einer Funktion Namens art_von_dreieck. Einmal rufst Du sie auf und übergibst ihr drei Parameter (7, 7 und 7) und einmal rufst Du sie ohne Parameter auf. ???

    In C wird das sogar kompilieren. Sollte eine Warning geben, aber laut Standard ist das soweit ich weiss immer noch erlaubt.

    Ich hatte mir auch erst gedacht dass das gar nicht gehen kann weil da kein Prototype für die Funktion ist, aber in C ist das eben erlaubt.

    Falsch ist es natürlich trotzdem.



  • Hallo Switch_24!

    Bei einem Dreieck ist die Summe zweier Seiten(egal welche), immer länger als die dritte Seite:

    (a + b) > c
    (a + c ) > b
    (b + c) > a

    Wenn allerdings zum Beispiel (a + b) <= c ist, dann liegt entweder eine fehlerhafte Eingabe oder eine Gerade vor.

    Zudem kannst du die Fläche nur aus dem Seitenlängen mit der Formel des Heron von Alexandria bestimmen.
    Wenn du die Seiten dann der Länge nach sortierst und die (Fläche * 2) / Längste_Seite berechnest, ist das die
    Grundlage, alle drei Winkel am Dreieck zu berechnen.

    Beim Vergleichen von Fließkommatypen egal ob float, double oder long double solltest du Vorsicht walten lassen.
    Schreibe dir eine Funktion, bei der du bestimmen kannst in wie weit die Variablen bei den Nachkommastellen gleich sind.
    Hier dazu nur ein kleines Beispiel:

    #include <iostream>
    #include <iomanip>
    #include <cmath>
    #include <limits>
     
    int compdouble(double da, double db, int stellen)
    {
     int rewer = -1, nachint_a = 0, nachint_b = 0, i, faktor = 1, vka, vkb;
     double nachkomma_a, vorkomma_a;
     double nachkomma_b, vorkomma_b;
     
      
     nachkomma_a = std::modf(da, &vorkomma_a);
     nachkomma_b = std::modf(db, &vorkomma_b);
     
     vka = vorkomma_a;
     vkb = vorkomma_b;
     
     std::cout << "Nachkomma_a: " << nachkomma_a << std::endl;
     std::cout << "Nachkomma_b: " << nachkomma_b << std::endl;
     
     if(vka == vkb)
     for (i = 0; i <= stellen; i++)
      {
       faktor *= 10;
       nachint_a = nachkomma_a * faktor;
       nachint_b = nachkomma_b * faktor;
       std::cout <<"nachint_a: " << std::setw(8) << nachint_a<< "   nachint_b: " << std::setw(8) <<  nachint_b << "   i:" << i << std::endl;
       if(nachint_a != nachint_b) break;
      }
     
      rewer = i;  // Gibt an, bis zu welcher Nachkommastelle die Zahlen gleich sind
     
     return rewer;	
    }
    
    int main()
    {
        int erge = 0;
    	double da, db;
    	
    	std::cout << "Bitte double-Wert eingeben: " ;
    	std::cin >> da;
    	std::cout << "Bitte 2ten double-Wert eingeben: " ;
    	std::cin >> db;
     
        erge = compdouble(da, db, 8);    
        std::cout << "Gleich bis Nachkomma-Stelle: " << erge << std::endl;
    	
     return 0;
    }
    Selbst bei ultralangen Schenkeln(etwa bei spitzwinkeligen Dreiecken), die gleich sind, kannst du einen der Schenkel hernehmen, um damit die Höhe zu bestimmen, welche zu 90 Grad rechtwinkelig auf diesem Schenkel steht, um damit die Winkel zu bestimmen. Bei einem rechtwinkeligen Dreieck ist die längste Seite immer die Hypotenuse. Teilt man diese in exakt zwei gleiche Teile und Zeichnet einen Halbkreis herum, so liegt der Schnittpunkt beider Schenkel auf dem Halbkreis.
    Bei stumpfwinkeligen Dreiecken ist die längste Seite eh immer die, auf welche die Höhe (90 Grad zur längsten Seite), das Dreieck quasi in zwei Teile zerteil und man so über asin, acos, atan die Winkel berechnen kann. Die Höhe so über die längst Seite zu berechnen hat später Vorteile, etwa weil diese als eine Art Richtungsanzeiger fungiert, wenn man den
    Kreis berechnet, der dieses Dreieck umschließt. Damit auch den Kreismittelpunkt dieses Kreises. Ist zum Beispiel interessant, wenn man etwa eine Stahlplatte hat, mit drei Passbohrungen darin in dem je ein Passstift steckt. Damit kann man dann den Durchmesser des Kreises berechnen, auf dem diese Drei Bohrungen liegen und dessen Kreismittelpunkt.
    Da wird zuerst über die Kartesischen Koordinaten der Bohrungen die Seiten des Dreiecks berechnet, dann die Fläche, die Winkel, Die Höhe und die Laqe der längsten Seite(n). Erst dann kannst du die Lage des Kreismittelpunktes berechnen der den Kreis bildet, auf dem die Bohrungen sitzen.
    
    Da du ja nur die Seitenlängen hast, musst du zuerst den Flächeninhalt berechnen, dann mindestens einen der Winkel.
    Erst dann kannst du den Sinussatz anwenden.


  • @rustyoldguy sagte in Flächeninhalt bestimmen:

    int compdouble(double da, double db, int stellen)

    Phew, ganz schön lang.

    Meistens ist es ausreichend, einfach die Differenz mit einem Wert nahe 0 zu vergleichen:

    bool almost_equal(double a, double b, double epsilon) {
       return std::abs(a - b) < epsilon;
    }
    

    Reicht für mich praktisch immer aus. Auch wenn man manchmal vielleicht lieber eine relative Ähnlichkeit testen will (also a/b1a/b \approx 1 statt ab0|a-b| \approx 0)



  • @rustyoldguy @wob Das ist ja alles nett, aber der OP ist bei Zahlen vs. Zeichen.

    @rustyoldguy In Deinem Post fehlt ein ``` nach Deinem Code.



  • Außerdem wird in seinem Code ja gar nicht mit Fließkommazahlen, sondern nur mit ganzen Zahlen, gerechnet.



  • Für Leute mit gcc, welche
    Kompatibilität zu Microsofts 'double Epsilon' suchen:

    double Epsilon(void)
    {
    double floatEps = 1;
    
        while (1 + floatEps / 2 != 1)
            floatEps /= 2;
    return floatEps;
    }
    

    Das kleine Proggi war nur ein Beispiel. Quasi ein Vorschlag was man kochen könnte. Kein fertiges Rezept.



  • @rustyoldguy sagte in Flächeninhalt bestimmen:

    Für Leute mit gcc, welche
    Kompatibilität zu Microsofts 'double Epsilon' suchen:

    Hm? Wer sucht das hier? Wozu kann man es in diesem Zusammenhang nutzen?

    In C++ könnte deine Funktion durch
    std::numeric_limits<double>::epsilon()
    ersetzt werden. Vielleicht gibt es in C auch etwas entsprechendes fertiges?


  • Mod

    Bloß ist der Epsilonvergleich völlig sinnlos, weil er die wichtigste Eigenschaft von Fließkommazahlen, Skalierbarkeit, nicht berücksichtigt. Besser: Auf den Abstand gucken, im Sinne von wie viele Floatwerte zwischen den beiden Werten liegen können. Das ist bei IEEE 754 Zahlen sogar bewusst einfach gemacht, da diese auf Binärebene so codiert sind, dass dieser Abstand gleich der Differenz der Integerinterpretation der Binärcodierung ist.



  • Hallo SeppJ!

    Auf stackoverflow habe ich dazu folgenden Kommentar gefunden:

    "I don't know what they were smoking when they wrote that. Double.Epsilon is the smallest representable non-denormal floating point value that isn't 0. All you know is that, if there's a truncation error, it will always be larger than this value. Much larger."

    https://stackoverflow.com/questions/2411392/double-epsilon-for-equality-greater-than-less-than-less-than-or-equal-to-gre

    Der Erste Teil des Kommentar bezieht sich anscheinend auf die Programmierer von MS.



  • @rustyoldguy sagte in Flächeninhalt bestimmen:

    Für Leute mit gcc, welche
    Kompatibilität zu Microsofts 'double Epsilon' suchen:

    double Epsilon(void)
    

    Es gibt dafür extra ein Makro

    #include <float.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int main () {
        printf ("%e\n", DBL_EPSILON);
    
        return EXIT_SUCCESS;
    }
    

    Wenn man so Fragen hat sollte man sich mit dem Inhalt von float.h unbedingt vertraut machen.



  • So hätte ich das gemacht; hoffe, habe nix übersehen:

    #include <iostream>
    #include <map>
    #include <math.h>
    
    using namespace std;
    
    enum Typ_Dreieck
    {
        gleichschenklig = 1,
        rechtwinklig = 2,
        beliebig = 0
    };
    
    class Dreieck
    {
    private:
    public:
        Dreieck(float a, float b, float c);
        ~Dreieck();
        float a, b, c;
        const float e = 0.1;
    
        bool is_equal(float a, float b) const
        {
            return fabs(a - b) - e <= 0;
        }
    
        bool is_gleichschenklig() const
        {
            return is_equal(a, b) || is_equal(a, c) || is_equal(b, c);
        }
    
        bool is_rechtwinklig() const
        {
            float a2 = a * a;
            float b2 = b * b;
            float c2 = c * c;
            if (is_equal(a, b))
                return is_equal(a2 + b2, c2);
            if (is_equal(a, c))
                return is_equal(a2 + c2, b2);
            if (is_equal(b, c))
                return is_equal(b2 + c2, a2);
            return false;
        }
    
        Typ_Dreieck get_type() const
        {
            if (is_rechtwinklig())
                return Typ_Dreieck::rechtwinklig;
            if (is_gleichschenklig())
                return Typ_Dreieck::gleichschenklig;
            return Typ_Dreieck::beliebig;
        }
    };
    
    Dreieck::Dreieck(float a, float b, float c) : a{a}, b{b}, c{c} {};
    
    Dreieck::~Dreieck()
    {
    }
    
    const char *type_to_string(Typ_Dreieck e)
    {
        const map<Typ_Dreieck, const char *> my_map{
            {Typ_Dreieck::beliebig, "beliebig (type 0)"},
            {Typ_Dreieck::gleichschenklig, "gleichschenklig (type 1)"},
            {Typ_Dreieck::rechtwinklig, "rechtwinklig (type 2)"}};
        auto it = my_map.find(e);
        return it == my_map.end() ? "Out of range" : it->second;
    }
    
    ostream &operator<<(ostream &strm, const Dreieck &d)
    {
        return strm << "Dreieck(" << d.a << ", " << d.b << ", " << d.c << ", " << type_to_string(d.get_type()) << ")";
    }
    
    int main(int argc, char **argv)
    {
        cout << Dreieck(1.414, 1.414, 2) << endl;
        cout << Dreieck(1, 2, 3) << endl;
        cout << Dreieck(4, 4, 0.001) << endl;
        return EXIT_SUCCESS;
    }
    

    Edit: Ach klar habe ich etwas übersehen...:

        bool is_rechtwinklig() const
        {
            float a2 = a * a;
            float b2 = b * b;
            float c2 = c * c;
            return is_equal(a2 + b2, c2) || is_equal(a2 + c2, b2) || is_equal(b2 + c2, a2);
        }
    
    int main(int argc, char **argv)
    {
        cout << Dreieck(15, 20, 25) << endl;
        cout << Dreieck(1.414, 1.414, 2) << endl;
        cout << Dreieck(1, 2, 3) << endl;
        cout << Dreieck(4, 4, 0.001) << endl;
        return EXIT_SUCCESS;
    }
    

    Ersteres Dreieck wäre ohne Änderung nicht rechtwinklig gewesen...



  • Sorry, immer noch falsch.
    Ein beliebiges oder gleichschenkliges Dreieck KANN rechtwinklig oder nicht rechtwinklig sein. Das eine bedingt oder schließt das andere nicht aus. Man braucht zwei enum: Typ_Schenkel_Dreieck und Typ_Winkel_Dreieck.



  • Das sollten jetzt alle Fälle sein...

    #include <iostream>
    #include <map>
    #include <string>
    #include <math.h>
    
    using namespace std;
    
    enum Typ_Schenkel_Dreieck
    {
        beliebig,
        gleichschenklig,
        gleichseitig
    };
    
    enum Typ_Winkel_Dreieck
    {
        spitzwinklig,
        stumpfwinklig,
        rechtwinklig
    };
    
    class Dreieck
    {
    private:
    public:
        float a, b, c;
        const float e = 0.1;
        float aw, bw, cw;
        Dreieck(float a, float b, float c) : a{a}, b{b}, c{c}
        {
            float a2 = a * a, b2 = b * b, c2 = c * c;
            aw = acosf((b2 + c2 - a2) / (2 * b * c)) * (180 / 3.14159265358979323846);
            bw = acosf((a2 + c2 - b2) / (2 * a * c)) * (180 / 3.14159265358979323846);
            cw = acosf((a2 + b2 - c2) / (2 * a * b)) * (180 / 3.14159265358979323846);
        };
    
        ~Dreieck()
        {
        }
    
        bool is_equal(float a, float b) const
        {
            return fabs(a - b) - e <= 0;
        }
    
        Typ_Schenkel_Dreieck get_type_schenkel() const
        {
            if (is_equal(a, b) && is_equal(b, c))
                return Typ_Schenkel_Dreieck::gleichseitig;
            if (is_equal(a, b) || is_equal(a, c) || is_equal(b, c))
                return Typ_Schenkel_Dreieck::gleichschenklig;
            return beliebig;
        }
    
        Typ_Winkel_Dreieck get_type_winkel() const
        {
            if (is_equal(aw, 90) || is_equal(bw, 90) || is_equal(cw, 90))
                return Typ_Winkel_Dreieck::rechtwinklig;
            if (aw >= 90 || bw >= 90 || cw >= 90)
                return Typ_Winkel_Dreieck::stumpfwinklig;
            return Typ_Winkel_Dreieck::spitzwinklig;
        }
    };
    
    const char *type_to_string(Typ_Schenkel_Dreieck es, Typ_Winkel_Dreieck ew)
    {
        string s1, s2;
        switch (es)
        {
        case Typ_Schenkel_Dreieck::beliebig:
            s1 = "beliebig, ";
            break;
        case Typ_Schenkel_Dreieck::gleichschenklig:
            s1 = "gleichschenklig, ";
            break;
        case Typ_Schenkel_Dreieck::gleichseitig:
            s1 = "gleichseitig, ";
            break;
        default:
            s1 = "not defined";
            break;
        }
        switch (ew)
        {
        case Typ_Winkel_Dreieck::spitzwinklig:
            s2 = "spitzwinklig";
            break;
        case Typ_Winkel_Dreieck::stumpfwinklig:
            s2 = "stumpfwinklig";
            break;
        case Typ_Winkel_Dreieck::rechtwinklig:
            s2 = "rechtwinklig";
            break;
        default:
            s2 = "not defined";
            break;
        }
        return (s1 + s2).c_str();
    }
    
    ostream &operator<<(ostream &strm, const Dreieck &d)
    {
        return strm << "Dreieck(" << d.a << ", " << d.b << ", " << d.c << ", " << d.aw << ", " << d.bw << ", " << d.cw << ","
                    << endl
                    << type_to_string(d.get_type_schenkel(), d.get_type_winkel()) << ")";
    }
    
    int main(int argc, char **argv)
    {
        cout << Dreieck(15, 20, 25) << endl;
        cout << Dreieck(1.414, 1.414, 2) << endl;
        cout << Dreieck(2, 2, 3) << endl;
        cout << Dreieck(4, 4, 1) << endl;
        return EXIT_SUCCESS;
    }
    

Log in to reply