Probleme mit dem Taschenrechner-Programm



  • @aeon
    Also ich habe die Aufgabenstellung nicht so verstanden, dass du den Ausdruck nicht erst komplett einlesen darfst. So wie ich das verstanden habe, sollst du sogar zuerst die komplette Zeile einlesen.

    Verwendest du die sin()-Funktion von C? Dann musst du aufpassen, dass der Parameter im Bogenmaß angegeben werden muss. Oder hast du ein Problem den Wert zwischen den Klammern in der Eingabezeile rauszulesen? Dann wär ein bisschen Quellcode nicht schlecht 😉 (bitte aber nur den Teil mit deiner Sinusbehandlung).



  • Ich würde mir einen schönen Platz in der Grammatik suchen, wo ich Funktionen unterbringen kann. Die <factor>-Produktion zu erweitern wär mein erster Gedanke.

    <factor> ::= ( <expression> ) | <number> | <function> ( <expression> ) ;
    <function> :: = sin | cos | ln etc.
    


  • Wenn du morgen erst dein Testat hast, solltest du dir nicht alzu viel
    Sorgen um das Klammernzählen machen. Durch die ganzen getchars in dem Programm
    aus der Vorlsung kann man das gar nicht so leicht in "hübscher" Art und Weise
    einbauen. Hat selbst unsere Übungsleiterin nicht auf anhieb geschafft: Sie
    musste die Musterlösung korriegieren 🙂 Bei der Aufgabe sind die Prüfer ein
    bissl großzügig.
    Hatte mein Testat schon Mittwoch 😉

    Hab das sin/exp - Problem quasi so gelöst wie Bashar.

    Edit: Ich würd mir noch mal deine Funktion didgits anschauen. Sieht so aus,
    als hättest du da einigen redundanten Code drin, da du ja entweder eine
    ganze Zahl oder pi einliest - andere Fälle kannst du ignorieren, da nur die
    Klammern auf Fehler geprüft werden sollen.



  • @AJ wir sollen eine eigene sin()-fkt benutzen aber es macht keinen unterschied wir benutzen an unserer uni standartmäßig das bogenmaß, es steht dabei wenn wir das gradmaß benutzen sollen.

    Wenn du interesse hast han selbst gebauten sinusfkt, ich habe 3 versionen im angebot: eine approximation mit dem horner-schema, mit der sinusreihe und noch eine version die zusätzlich mit neville-interpolation einen genaueren wert berechnet.

    Vielen dank für eure Hilfe. Also heute haben wir das programm abgeben müssen und einer mit dem ich zusammenabgegeben habe hat ein funktionierendes programm hinbekommen, unserem tutor hat das programm sogar noch besser gefallen als die vorgabe die wir hatten. er hat ein wenig überlegt und hat sich dann für eine pointer of pointer methode entschieden, die war dann einfacher zu handhaben.

    den einzigen fehler den das programm noch prodziert ist das mit den klammern.
    Wenn man zwei klammer in dieser -> )( Reihenfolge eingibt findet das programm keinen fehler, da es nur die anzahl der offenen klammern incrementeiert bzw wieder decrementiert wird und dann geprüfft ob die anzahl == 0 ist.

    hier erstmal das (fast)Feritge taschenrechner programm:

    #include <stdio.h>
    #include <math.h>
    #define PI	3.14159265358979323846
    
    double expression(char **ch);/* pointer auf pointer, um in den Funktionen den pointer auf den eingabestring inkrementieren zu koennen */
    double term(char **ch);
    double factor(char **ch);
    double number(char **ch);
    
    /******Sinus********************************************************************/
    double sinus (double x);
    {
        double Wert,Summand,Wert_alt;
        int m,n,a=1;
    
        if (x<0)/*für alle negativen x wird a negativ und x positiv*/
         {
         a=-1;
         x=-x;
         }
    
        x=fmod(x,(2*PI));/*x wird auf das Intervall [0,2PI] Reduziert*/
    
        if (x>PI)/*für x>PI a wird mit -1 multipliziert und x wird am Wendepunkt gespiegelt*/
         {
         a=-a;
         x=(2*PI)-x;
         }
    
        if (x>(PI/2))/*a bleibt unverändert und x auf das Intervall [0,PI/2] geschickt*/
         {
         x=(PI-x);
         }
    
        m=0;
        n=1;
        Wert=x;/*Initialisierung der Variablen*/
        Summand=x;
        Wert_alt=x+1;
    
        while(Wert_alt!=Wert)/*Beginn der while- Schleife mit Abbruchbedingung wenn der alte Wert=Summe Alterwert& neues Glied*/
          {
          m=m+2;/*m&n jeweils+2 ergeben die hinzukommenden Glieder der Fakultäten*/
          n=n+2;
          Summand=-Summand*x*x/m/n;/*Festlegung des neuen Summanten der alterniert*/
          Wert_alt=Wert;/*wertalt=Wert neu*/
          Wert=Wert+Summand;/*Wert= Summe des alten Wertes und des Gliedes*/
          }
        return(a*Wert);
        }
    
    double normalize (double x) /* normalize the x value to a value between 0 and Pi/2 to improve results*/
    {
    	if (x < 0) x *= -1.0; /* same as abs(x) */
    	x = fmod(x, 2*PI); /* as sin(x) has a period of 2Pi the modulo operation doesnt change the result  */
    
    	if (x <= (PI/2)) return x; /* these calculations are possible because sin(x) is periodical */
    	if (x > PI) return ((-2*PI) + x);
    	if (x <= PI) return (PI - x);
    
    	return x;
    }
    
    /******Expression***************************************************************/
    /* zustaendig fuer summen und differenzen, alles andere wird an term weitergereicht*/
    double expression(char **ch)
    {
      double d = 0.0;/* variable fuer den Rueckgabewert */
      switch (**ch)
       {/* erster term :  + oder -, jenachdem term ergebnis interpretieren */
        case '+':  (*ch)++; d=  term(ch); break;/* (*ch)++; = geht ein zeichen weiter */
        case '-':  (*ch)++; d= -term(ch); break;
        default :  d= term(ch); break;
       }
      while (1)
        switch (**ch)
    		{/* dasselbe gilt fuer alle weiteren terme, bis keiner mehr da ist*/
          case '+':  (*ch)++; d= d + term(ch); break;
          case '-':  (*ch)++; d= d - term(ch); break;
          default :  return(d);
        }
    } /* expression */
    /******Term*********************************************************************/
    /* hier werden produkte und quotienten verarbeitet und an factor uebergeben*/
    double term(char **ch)
    {
      double d = factor(ch);/* ersten teil sofort an factor weiterreichen */
      while (1)
      switch (**ch)
       {/* folgen weitere teile (mit * oder /), entsprechend zu d */
    	/* dazurechnen und rest an factor uebergeben */
          case '*':  (*ch)++; d = d * factor(ch); break;
          case '/':  (*ch)++; d = d / factor(ch); break;
          default :  return(d);
       }
    } /* term */
    
    /******Faktor*******************************************************************/
    /* ueberpruefen, ob ein weiterer ausdruck oder nur eine zahl folgt */
    double factor(char **ch)
    {
      double d = 0.0;
      switch (**ch)
       {
        case '(':  (*ch)++; d = expression(ch); (*ch)++; break;/* weiterer ausdruck -> an expression uebergeben*/
        case 's': /* sinus -> folgender ausdruck an expression */
    			if ((*(++(*ch)) == 'i') && (*(++(*ch)) == 'n'))
    			{
    				(*ch)++;/* 2 zeichen weiter ( fuer 'n' und '(' )*/
    				(*ch)++;
    				d = sinus(expression(ch));
    				(*ch)++;
    			}
    			break;
        case 'c':/* cosinus -> folgender ausdruck an expression */
    			if ((*(++(*ch)) == 'o') && (*(++(*ch)) == 's'))
    			{
    				(*ch)++; /* 2 zeichen weiter ( fuer 's' und '(' )*/
    				(*ch)++;
    				d = sinus(expression(ch)+(PI/2));
    				(*ch)++;
    			}
    			break;
    		case 'e':/* exponentialfkt -> folgender ausdruck an expression */
    			if ((*(++(*ch)) == 'x') && (*(++(*ch)) == 'p'))
    			{
    				(*ch)++;/* 2 zeichen weiter ( fuer 'p' und '(' )*/
    				(*ch)++;
    				d = exp(expression(ch));
    				(*ch)++;
    			}
    			break;
    		default :  d = number(ch);/* der einfachste fall, zahl folgt -> an number */
    	}
    	return(d);
    } /* factor */
    
    /******Number*******************************************************************/
    /* liest zahl oder sonderzeichen ein */
    double number(char **ch)
    {
      double s = 1.0, d = 0.0, n = 10.0;
      switch (**ch)/* vorzeichen (signum) der zahl einlesen */
    	{
        case '+':  (*ch)++; break;
        case '-':  (*ch)++; s = -1; break;
      }
    	/* sonderzeichen */
    	if ((**ch == 'p') && (*(++(*ch)) == 'i'))/* auf pi testen */
    	{
    		d = PI;
    		(*ch)++;
    	}
    	else
    	{/* zahl einlesen */
    		while ( ('0'<=**ch) && (**ch<='9') )
    		{/* vor dem punkt */
    			d = 10*d + (**ch-'0');
    			(*ch)++;
    		}
    		if (**ch == '.')
    		{/* nach dem punkt */
    			(*ch)++;
    			while ( ('0'<=**ch) && (**ch<='9') )
    			{
    				d = d + ((**ch-'0') / n);
    				n *= 10;/* funktioniert natuerlich nur fuer begrenzt viele stellen */
    				(*ch)++;
    			}
    		}
    	}
      return(s*d);
    } /* number */
    
    /******Hauptprogramm************************************************************/
    int main(void)
    {
    	char ch[256]={'\0'};/* fuer die eingabe, mit nullen vollschreiben; das eine '\0' braucht z.B. der MS compiler */
    	char *pch;/* pointer auf anfg von ch */
    	int br = 0, n = 0;
    
    	printf("Taschenrechner (Druecke q zum Beenden)\n");
    	pch = ch; /* s.o. */
    	printf(">");/* alternativ auch "C:\>" oder "user@machine:~ >" */
      scanf("%s", ch);
      while (ch[0]!='q')/* mit q beenden */
    	{
    	br = 0;
    	n = 0;
    	while (ch[n] != '\0')/* anz der klammern (brackets) bis zum \0 zaehlen*/
    	{
    		if (ch[n] == '(') br++;/* br wird <0 wenn zuviele ')', sonst >0 d.h. zuviele '(' */
    		if (ch[n] == ')') br--;
    		n++;
    	}
      if (br == 0)/* Klamemr-anzahl-richitg */
    		printf(" = %f\n", expression(&pch) ); /*<--- hier faengt alles an !, pointer auf pointer auf anfg vom eingabefeld */
      else  /* Klammerfehler */
    		printf("error - check brackets. %dx '%c' missing.\n", ((br<0)?-br:br), ((br<0)?'(':')') );
    	pch = ch; /* wieder auf feldanfang, wird ja von den fkt veraendert */
    	printf(">");
    	scanf("%s", ch);
      }
      return 0;
    } /* main */
    


  • Die Sinus-Funktion mit Horner-Schema:

    #include <stdio.h>
    #include <math.h>
    #define pi 3.14159265358979323846
    
    double sinus(double x)
    {
    
      double pi2 = 2 * pi;
      double pi1 = pi;
      double piHalb = 0.5 * pi; 
    
      int sign =1; /*dient zum speichern des Vorzeichens)*/
    
      /*Ändert x, bis x im Intervall [0,pi/2] liegt.  
      Das Vorzeichen wird extern gespeichert*/
      if (x < 0) { x *= -1.0; sign *= -1; }
      if (x > 2 * pi) { x = fmod(x,pi2); }
      if (x > pi1) { x = ( pi2 - x); sign *= -1; }
      if (x > piHalb) { x = pi1 - x; };
    
      /*Berechnung von sin(x)*/
      x= sign*(x*(1-x*x/6*(1-x*x/20*(1-x*x/42))));
    
      return(x);
    }; /*Sinus*/
    

    Hier die Sinus-Fkt mit Sin-Reihen-Approximation

    #include <stdio.h>
    #include <math.h>
    #define pi 3.14159265358979323846;
    
    double sinus(double x)
    {
      double oldres = 2, /*altes Ergebnis*/
             res    = 0, /*neues Ergebnis*/
             add    = 0; /*Einzelsummand aus Sinusreihe*/
      int    sign   = 1; /*dient zum speichern des Vorzeichens vom Ergebniss*/
      long   k      = 1; /*laufvariable*/
    
      double pi2 = 2 * pi;
      double pi1 = pi;
      double piHalb = 0.5 * pi; 
    
      /*Ändert x, bis x im Intervall [0,pi/2] liegt.  
      Das Vorzeichen wird extern gespeichert*/
      if (x < 0){x *= -1.0; sign *= -1;}
      if (x > pi2)x = fmod(x,pi2);
      if (x > pi1) {x = (pi2-x); sign *= -1; }
      if (x > piHalb) {x = pi1 - x;};
    
      /*Berechnung von sin(x)*/
      add = res = x;/*Erstes Glied der Summe(k=0)*/
      while (oldres != res)
      {
        oldres = res;
        add *= -(x*x)/(2*k*(2*k+1));/* (x^(2k+1))/((2k+1)!)ab k=1 aufmultipliziert*/
        k++;
        res += add;
    
      }  
      res *= sign; 
      return(res);
    }; /*sinus*/
    

    Hier Die Sinus-Fkt mit zusätzlich Neville-Interpolation

    /* Fkt berechnet den Sinus mit hilfe von Neville-Interpolation*/
    double sinus (double x, short st)/* x ist x-wert, st: anzahl der Stützwerte*/
    {
      short   a, b; /*Laufvariablen für die for-schleifen*/
      double  X[st],/*Stützwerte-Array*/
              Y[st];/*Stützstellen-Array*/
    
      double pi2 = 2 * pi;
      double pi1 = pi;
      double piHalb = 0.5 * pi; 
    
      int sign =1; /*dient zum speichern des Vorzeichens)*/
    
      /*Ändert x, bis x im Intervall [0,pi/2] liegt.  
      Das Vorzeichen wird extern gespeichert*/
      if (x < 0) { x *= -1.0; sign *= -1; }
      if (x > 2 * pi) { x = fmod(x,pi2); }
      if (x > pi1) { x = ( pi2 - x); sign *= -1; }
      if (x > piHalb) { x = pi1 - x; };
    
      /*Erzeugung von Stützstellen und werten*/
      for ( a=0 ; a<st ; a++ )
      {
        X[a] = a * 0.5 / st * pi;
        Y[a] = SinOld(X[a]); /*SinOld() ist die Sin()-Fkt die den sinus mit
                               der Sinus-Reihe berechnet.*/
      }
    
      /* Interpolation des Wertes*/
      for ( b=1; b<st; b++)
      {
    	 for ( a=0; a<(st-b); a++)
    	 {
    		Y[a] = Y[a+1] + (Y[a+1] - Y[a]) / ((x - X[a]) / (x-X[a+b]) - 1);
    	 }
      }   
      Y[0]*=sign;  
      return(Y[0]);
    }/*Sinus*/
    

    Wer Interesse hat Die Aufgaben-Blätter zu diesen Lösungen findet ihr Hier es sind die Aufgaben 5 und 6:
    http://www.ti3.tu-harburg.de/ProgMetho/



  • )( findest du, indem du brüfst, ob br zwischendruch negativ wird.



  • Danke für die Idee, hab gar net dran gedacht...

    negativ, das einfachste entfällt einem meistens zuerst,



  • Wozu soll das Klammernzählen gut sein? Der Parser wirds schon merken, wenn da was nicht stimmt.



  • @Bashar: Ja der Parser merkt es, gibt aber keine Fehlermeldung zurück sondern nur ein falsches ergebnis.
    Deswegen das klammerzählen, es dient zum abfangen von fehlern und damit niemand mit einem falschen ergebnis weiter rechnet.



  • Dann muss man den Parser halt so schreiben, dass er nen Fehler ausgibt.


Anmelden zum Antworten