Rechnen in c++



  • Schönen guten Abend Euch.
    Hab mal eine fixe Frage, hab ich irgendetwas verpasst aber warum geht
    diese Rechnung in C nicht?

    y = m_nZ/m_Nn*nVal;
    

    Bekomme ein falsches Ergebnis.
    Wenn ich aber

    y = m_nZ * nVal / m_Nn;
    

    mache funktioniert es, an was liegt das ?

    Liebe Grüße



  • Es wäre gut zu wissen, welchen Typ die beteiligten Variablen haben. Nach (alter) Namenskonventionen (n) sind dies Ganzzahlen. Das Ergebnis der Teilausdrücke ist vom gleichen Typ. Die Abarbeitung erfolgt von links nach rechts.
    Beispiel:

    m_nZ=4,m_Nn=8,nVal=4:
    ----------------------------
    m_nZ/m_Nn*nVal
    4/8=0;0*4=0
    vs.
    m_nZ*nVal/m_Nn;
    4*4=16;16/8=2
    

    Eine Möglichkeit wäre, Teilausdrücke als Gleitkommazahlen berechnen zu lassen:

    y = 1.f*m_nZ/m_Nn*nVal; // float
    // oder
    y = 1.0*m_nZ/m_Nn*nVal; // double
    // oder durch Umwandlung
    y = double(m_nZ)/m_Nn*nVal;
    

    Genauigkeiten und mögliche Abweichungen lassen sich natürlich auch berechnen (abhängig von Mantisse und Exponent der Typen).



  • ich habe es in meinem Versuch so gemacht (Funktion):

    double y;
    
    	y = m_nZ/m_Nn*nVal;
    

    m_nZ = 1 , m_Nn = 2 , nVal = 0.1;

    1/2 * 0.1 = 0,05

    und y returned. Aber laut meiner Rechnung kommt 0,05 raus.

    Aber es kommt "0" zurück.

    Mein Prof hat es so gemacht und es kommt das richtige:

    return nVal*m_nZ/m_Nn;
    

    Bei meiner Rechnung ... Was rechnet der Compiler für nen "BullShit" ? 😃

    Oder handelt er nach irgendwelchen Regeln?



  • Die Berechnung hängt NICHT vom Ergebnistyp (also den von y) ab, sondern von den Typen der Variablen rechts vom =-Zeichen! Erst NACH der Berechnung wird dann in den Typ auf der linken Seite konvertiert.

    Sind z.B. m_nZ und m_Nn beide ints (bzw. ganzzahlige Typen), dann wird die Division auch ganzzahlig durchgeführt. Probiere daher 1.0*m_nZ/m_Nn*nVal .

    Eine andere mögliche Ursache: wenn die Zahlen besonders groß/klein sind, können durch Rundungen starke Fehler erzeugt werden. Daher so rechnen, dass man gut im Bereich bleibt, der dargestellt werden kann



  • omg danke @wob daran kann es liegen. Mein Konstruktor initalisiert mein Objekt mit Integer .... 😮 😮

    Damit erklärt es sich 🙄

    Aber warum klappt es bei meinem Prof so ...

    return nVal*m_nZ/m_Nn;
    

    Wenn ich es so mache:

    return m_nZ/m_Nn*nVal;
    

    klappt es nicht...Was macht der Compiler?



  • buu2188 schrieb:

    omg danke @wob daran kann es liegen. Mein Konstruktor initalisiert mein Objekt mit Integer .... 😮 😮

    Damit erklärt es sich 🙄

    Aber warum klappt es bei meinem Prof so ...

    return nVal*m_nZ/m_Nn;
    

    Wenn ich es so mache:

    return m_nZ/m_Nn*nVal;
    

    klappt es nicht...Was macht der Compiler?

    // m_nZ = 1 , m_Nn = 2 , nVal = 0.1;

    Im zweiten Fall: wenn m_nZ/m_Nn integers sind, dann ist 1/2 = 0 also rechnest du 00.1
    Im ersten Fall rechnest du zuerst 0.1
    1 (das ist ein double, 0.1) und danach erst 0.1/2, bleibt also double.

    Versuch mal die zweite Rechnung als

    1.0/2.0*0.1;
    

    bzw: double m_nZ = 1.0 , m_Nn = 2.0 , nVal = 0.1;
    dann müsste die zweite Variante auch klappen.



  • buu2188 schrieb:

    omg danke @wob daran kann es liegen. Mein Konstruktor initalisiert mein Objekt mit Integer .... 😮 😮

    Die Frage ist gerade NICHT, womit du die Variablen initialisierst, sondern welchen Typ sie haben.

    Es ist also egal, ob du

    // a)
    double d = 1;
    // oder b)
    double d = 1.0;
    

    schreibst, denn im Fall a) wird die 1 in eine 1.0 umgewandelt.
    Wenn du dagegen hast:

    // c)
    int i = 1;
    // oder d)
    int i = 1.0;
    

    Wird bei d) die 1.0 in eine 1 umgewandelt.

    Die Berechnung folgt dann den üblichen Regeln (Punkt vor Strich, ansonsten von links nach rechts). Und für jeden Teilausdruck schaust du dir dann an, welche Typen miteinander verwurstet werden.

    int/int = int
    intint = int
    double
    int = double
    int*double = double
    usw.

    Wenn du also den Ausdruck
    double*int/int hast, dann wird zuerst double*int=double gerechnet, dann double/int=double. Also die gesamte Zeit als double!
    Bei int/int*double dagegen rechnest du erst int/int=int (also nur ganzzahliges Ergebnis!), dann int*double=double.

    Alles klar?


Anmelden zum Antworten