├── Screenshots ├── calculator.jpg ├── integral_1.jpg ├── integral_2.jpg └── title_screen.jpg ├── LICENSE ├── README.md ├── main.c └── Header ├── integral.h └── calculator.h /Screenshots/calculator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arasgungore/integral-calculator/HEAD/Screenshots/calculator.jpg -------------------------------------------------------------------------------- /Screenshots/integral_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arasgungore/integral-calculator/HEAD/Screenshots/integral_1.jpg -------------------------------------------------------------------------------- /Screenshots/integral_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arasgungore/integral-calculator/HEAD/Screenshots/integral_2.jpg -------------------------------------------------------------------------------- /Screenshots/title_screen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arasgungore/integral-calculator/HEAD/Screenshots/title_screen.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Aras Güngöre 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # integral-calculator 2 | 3 | A C project which can calculate the definite integral of any given real function using the midpoint method, trapezoidal rule, Simpson's rule, Boole's rule, and many other Newton-Cotes quadrature formulas. Alternatively, the project can be used to estimate the derivative of such functions and compute mathematical expressions according to the order of operations using recursive algorithms. 4 | 5 | 6 | 7 | ## Run on Terminal 8 | 9 | ```sh 10 | gcc main.c -o test 11 | test 12 | ``` 13 | 14 | 15 | 16 | ## Screenshots 17 | 18 |

19 | Screenshot 20 | Screenshot 21 | Screenshot 22 | Screenshot 23 |

24 | 25 | 26 | 27 | ## Author 28 | 29 | 👤 **Aras Güngöre** 30 | 31 | * LinkedIn: [@arasgungore](https://www.linkedin.com/in/arasgungore) 32 | * GitHub: [@arasgungore](https://github.com/arasgungore) 33 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "Header/integral.h" 2 | #include 3 | 4 | #define N_MIN pow(4, 8) 5 | #define N_MAX pow(4, 10) 6 | #define DX_MAX powl(4, -10) 7 | #define DX_MIN powl(4, -24) 8 | typedef enum { 9 | CALCULATOR_MODE='1', INTEGRAL_MODE, DERIVATIVE_MODE 10 | } Mode; 11 | int main() { 12 | printf( "Trigonometric functions:\n\tsin\n\tcos\n\ttan\n\tcot\n\tsec\n\tcsc/cosec" 13 | "\n\nHyperbolic trigonometric functions:\n\tsinh\n\tcosh\n\ttanh\n\tcoth\n\tsech\n\tcsch" 14 | "\n\nInverse trigonometric functions:\n\tasin/arcsin\n\tacos/arccos\n\tatan/arctan\n\tacot/arccot\n\tasec/arcsec\n\tacsc/arccsc" 15 | "\n\nExponential and logarithmic functions:\n\tsqr\n\tcube\n\tsqrt\n\tcbrt\n\texp\n\tlog\n\tln" 16 | "\n\nMiscellaneous functions:\n\tabs\n\tceil\n\tfloor\n\tround\n\tfact" 17 | "\n\nOperations:\n\t+\n\t-\n\t*\n\t/\n\t%%\n\t^\n\t!"); 18 | while(TRUE) { 19 | printf( "\n\nPress 1 to calculate expressions." 20 | "\nPress 2 to calculate the definite integral of functions using numerical integration." 21 | "\nPress 3 to calculate the derivate of functions using limit definition." 22 | "\nPress any other key to quit..."); 23 | switch(getch()) { 24 | case CALCULATOR_MODE: { 25 | printf("\n\nPress D to enable degrees, press any other key to enable radians."); 26 | const char key = getch(); 27 | while(TRUE) { 28 | Expression *expr = (Expression[]){{"", '\0', 0, key=='d' || key=='D'}}; 29 | printf("\n\nEvaluate the following algebraic expression: "); 30 | gets(expr->expression); 31 | if(!(strncmp(expr->expression, "exit", 4) && strncmp(expr->expression, "quit", 4))) 32 | break; 33 | expr->currentChar = expr->expression[0]; 34 | __mingw_printf("Answer: %.16Lg\n", parse(expr, ' ', 0.0)); 35 | } 36 | continue; } 37 | case INTEGRAL_MODE: { 38 | printf("\n\nPress D to enable degrees, press any other key to enable radians."); 39 | const char key = getch(); 40 | while(TRUE) { 41 | Integral *ig = (Integral[]){{0.0, 0.0, 0.0, {"", '\0', 0, key=='d' || key=='D'}}}; 42 | printf("\n\nVariable of integration: "); 43 | char variable; 44 | scanf("%c%*c", &variable); 45 | printf("Integrate the following function: "); 46 | gets(ig->expr.expression); 47 | if(!(strncmp(ig->expr.expression, "exit", 4) && strncmp(ig->expr.expression, "quit", 4))) 48 | break; 49 | printf("Enter the lower bound (from) and upper bound (to) respectively: "); 50 | Expression *lb_value = (Expression*) malloc(sizeof(Expression)), *ub_value = (Expression*) malloc(sizeof(Expression)); 51 | lb_value->currentPos = ub_value->currentPos = 0, lb_value->anglesAreDegrees = ub_value->anglesAreDegrees = key=='d' || key=='D'; 52 | scanf("%s%s%*c", lb_value->expression, ub_value->expression); 53 | ig->expr.currentChar = ig->expr.expression[0], lb_value->currentChar = lb_value->expression[0], ub_value->currentChar = ub_value->expression[0]; 54 | ig->lowerBound = parse(lb_value, ' ', 0.0), ig->upperBound = parse(ub_value, ' ', 0.0); 55 | free(lb_value), free(ub_value); 56 | unsigned int n; 57 | for(n=N_MIN;n<=N_MAX;n*=4) { 58 | ig->dx = (ig->upperBound - ig->lowerBound) / n; 59 | printf("\nFor n=%u intervals:", n); 60 | __mingw_printf("\n\tLower Riemann Sum:\t\t\t%.16Lg", lowerRiemannSum(ig, n, variable)); 61 | __mingw_printf("\n\tUpper Riemann Sum:\t\t\t%.16Lg", upperRiemannSum(ig, n, variable)); 62 | __mingw_printf("\n\tMidpoint Rule:\t\t\t\t%.16Lg", midpointRule(ig, n, variable)); 63 | __mingw_printf("\n\tTrapezoidal Rule:\t\t\t%.16Lg", trapezoidalRule(ig, n, variable)); 64 | ig->dx = (ig->upperBound - ig->lowerBound) / (2*n); 65 | __mingw_printf("\n\tSimpson's (1/3) Rule:\t\t\t%.16Lg", simpsonsRule(ig, 2*n, variable)); 66 | ig->dx = (ig->upperBound - ig->lowerBound) / (3*n); 67 | __mingw_printf("\n\tSimpson's 3/8 Rule:\t\t\t%.16Lg", simpsonsThreeEighthsRule(ig, 3*n, variable)); 68 | ig->dx = (ig->upperBound - ig->lowerBound) / (4*n); 69 | __mingw_printf("\n\tBoole's Rule:\t\t\t\t%.16Lg", boolesRule(ig, 4*n, variable)); 70 | __mingw_printf("\n\tMilne's Rule:\t\t\t\t%.16Lg", milnesRule(ig, 4*n, variable)); 71 | ig->dx = (ig->upperBound - ig->lowerBound) / (5*n); 72 | __mingw_printf("\n\t6-Point Closed Rule:\t\t\t%.16Lg", sixPointClosedRule(ig, 5*n, variable)); 73 | ig->dx = (ig->upperBound - ig->lowerBound) / (6*n); 74 | __mingw_printf("\n\tWeddle's Rule:\t\t\t\t%.16Lg", weddlesRule(ig, 6*n, variable)); 75 | puts(""); 76 | } 77 | } 78 | continue; } 79 | case DERIVATIVE_MODE: { 80 | printf("\n\nPress D to enable degrees, press any other key to enable radians."); 81 | const char key = getch(); 82 | while(TRUE) { 83 | Expression *expr = (Expression[]){{"", '\0', 0, key=='d' || key=='D'}}, *x_value = (Expression[]){{"", '\0', 0, key=='d' || key=='D'}}; 84 | printf("\n\nVariable of differentiation: "); 85 | char variable; 86 | scanf("%c%*c", &variable); 87 | printf("Differentiate the following function: "); 88 | gets(expr->expression); 89 | if(!(strncmp(expr->expression, "exit", 4) && strncmp(expr->expression, "quit", 4))) break; 90 | printf("Enter the %c value: ", variable); 91 | gets(x_value->expression); 92 | expr->currentChar = expr->expression[0], x_value->currentChar = x_value->expression[0]; 93 | long double value = parse(x_value, ' ', 0.0), dx; 94 | for(dx=DX_MAX;dx>=DX_MIN;dx/=4.0) 95 | __mingw_printf("Derivative at point %c=%Lg for d%c=%Lg: %.16Lg\n", variable, value, variable, dx, (parse(expr, variable, value+dx) - parse(expr, variable, value)) / dx); 96 | } 97 | continue; } 98 | default: 99 | exit(0); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Header/integral.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTEGRAL_H_ 2 | #define _INTEGRAL_H_ 3 | 4 | #include "calculator.h" 5 | 6 | // header which contains integration methods 7 | 8 | // integral struct declaration 9 | typedef struct { 10 | long double lowerBound, upperBound, dx; 11 | Expression expr; 12 | } Integral; 13 | 14 | // function declarations 15 | long double riemannSum(Integral *ig, const unsigned int n, const char variable, long double xi); 16 | long double lowerRiemannSum(Integral *ig, const unsigned int n, const char variable); 17 | long double upperRiemannSum(Integral *ig, const unsigned int n, const char variable); 18 | long double midpointRule(Integral *ig, const unsigned int n, const char variable); 19 | long double trapezoidalRule(Integral *ig, const unsigned int n, const char variable); 20 | long double trapezoidalOpenRule(Integral *ig, const unsigned int n, const char variable); 21 | long double simpsonsRule(Integral *ig, const unsigned int n, const char variable); 22 | long double simpsonsThreeEighthsRule(Integral *ig, const unsigned int n, const char variable); 23 | long double simpsonsExtendedRule(Integral *ig, const unsigned int n, const char variable); 24 | long double boolesRule(Integral *ig, const unsigned int n, const char variable); 25 | long double milnesRule(Integral *ig, const unsigned int n, const char variable); 26 | long double weddlesRule(Integral *ig, const unsigned int n, const char variable); 27 | long double sixPointClosedRule(Integral *ig, const unsigned int n, const char variable); 28 | 29 | 30 | // calculates the definite integral according to Riemann sum 31 | long double riemannSum(Integral *ig, const unsigned int n, const char variable, long double xi) { 32 | long double sum = 0.0; 33 | unsigned int i; //dx=(b-a)/n, xi=a+i*dx ==> integral = f(x0)*dx + f(x1)*dx + f(x2)*dx + ... + f(x(n-1))*dx = (f(x0) + f(x1) + f(x2) + ... + f(x(n-1)))*dx = sigma(f(xi))*dx 34 | for(i=0;iexpr, variable, xi += ig->dx); 35 | return ig->dx * sum; 36 | } 37 | 38 | // calculates the definite integral according to lower Riemann sum 39 | long double lowerRiemannSum(Integral *ig, const unsigned int n, const char variable) { 40 | return riemannSum(ig, n, variable, ig->lowerBound - ig->dx); 41 | } 42 | 43 | // calculates the definite integral according to upper Riemann sum 44 | long double upperRiemannSum(Integral *ig, const unsigned int n, const char variable) { 45 | return riemannSum(ig, n, variable, ig->lowerBound); 46 | } 47 | 48 | // calculates the definite integral according to midpoint Riemann sum 49 | long double midpointRule(Integral *ig, const unsigned int n, const char variable) { 50 | return riemannSum(ig, n, variable, ig->lowerBound - ig->dx/2.0); 51 | } 52 | 53 | // calculates the definite integral according to trapezoidal 2-point rule of closed type 54 | long double trapezoidalRule(Integral *ig, const unsigned int n, const char variable) { 55 | long double sum = 0.0, xi = ig->lowerBound; 56 | unsigned int i; 57 | for(i=1;iexpr, variable, xi += ig->dx); 58 | return ig->dx * ((parse(&ig->expr, variable, ig->lowerBound) + parse(&ig->expr, variable, ig->upperBound)) / 2.0 + sum); 59 | } 60 | 61 | // calculates the definite integral according to trapezoid method of open type 62 | long double trapezoidalOpenRule(Integral *ig, const unsigned int n, const char variable) { 63 | if(n%3) { 64 | puts("\nInvalid partition for Open Trapezoidal Rule.\nn (number of intervals) must be a multiple of 3."); 65 | exit(1); 66 | } 67 | long double sum = 0.0, xi = ig->lowerBound; 68 | unsigned int i; 69 | for(i=1;iexpr, variable, xi += ig->dx); 71 | sum += parse(&ig->expr, variable, xi += ig->dx); 72 | xi += ig->dx; 73 | } 74 | return 1.50 * ig->dx * sum; 75 | } 76 | 77 | // calculates the definite integral according to Simpson's 1/3 3-point rule 78 | long double simpsonsRule(Integral *ig, const unsigned int n, const char variable) { 79 | if(n%2) { 80 | puts("\nInvalid partition for Simpson's (1/3) Rule.\nn (number of intervals) must be even."); 81 | exit(1); 82 | } 83 | long double sum1 = 0.0, sum2 = 0.0, xi = ig->lowerBound; 84 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 85 | unsigned int i; 86 | for(i=2;iexpr, variable, xi += ig->dx); 88 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 89 | } 90 | return ig->dx * (parse(&ig->expr, variable, ig->lowerBound) + parse(&ig->expr, variable, ig->upperBound) + 4.0*sum1 + 2.0*sum2) / 3.0; 91 | } 92 | 93 | // calculates the definite integral according to Simpson's 3/8 4-point rule 94 | long double simpsonsThreeEighthsRule(Integral *ig, const unsigned int n, const char variable) { 95 | if(n%3) { 96 | puts("\nInvalid partition for Simpson's 3/8 Rule.\nn (number of intervals) must be a multiple of 3."); 97 | exit(1); 98 | } 99 | long double sum1 = 0.0, sum2 = 0.0, xi = ig->lowerBound; 100 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 101 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 102 | unsigned int i; 103 | for(i=3;iexpr, variable, xi += ig->dx); 105 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 106 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 107 | } 108 | return 0.3750 * ig->dx * (parse(&ig->expr, variable, ig->lowerBound) + parse(&ig->expr, variable, ig->upperBound) + 3.0*sum1 + 2.0*sum2); 109 | } 110 | 111 | // calculates the definite integral according to alternative extended Simpson's rule, which is obtained by taking the mean of the original composite Simpson's rule and 3/8 Simpson's rule 112 | long double simpsonsExtendedRule(Integral *ig, const unsigned int n, const char variable) { 113 | if(n<8) { 114 | puts("\nInvalid partition for Alternative Extended Simpson's Rule.\nn (number of intervals) must be at least 8."); 115 | exit(1); 116 | } 117 | long double sum = 0.0, xi = ig->lowerBound + 3.0*ig->dx; 118 | unsigned int i; 119 | for(i=7;iexpr, variable, xi += ig->dx); 120 | return ig->dx * ((17.0*(parse(&ig->expr, variable, ig->lowerBound) + parse(&ig->expr, variable, ig->upperBound)) 121 | + 59.0*(parse(&ig->expr, variable, ig->lowerBound + ig->dx) + parse(&ig->expr, variable, ig->upperBound - ig->dx)) 122 | + 43.0*(parse(&ig->expr, variable, ig->lowerBound + 2.0*ig->dx) + parse(&ig->expr, variable, ig->upperBound - 2.0*ig->dx)) 123 | + 49.0*(parse(&ig->expr, variable, ig->lowerBound + 3.0*ig->dx) + parse(&ig->expr, variable, ig->upperBound - 3.0*ig->dx))) / 48.0 + sum); 124 | } 125 | 126 | // calculates the definite integral according to Boole's 5-point rule 127 | long double boolesRule(Integral *ig, const unsigned int n, const char variable) { 128 | if(n%4) { 129 | puts("\nInvalid partition for Boole's Rule.\nn (number of intervals) must be a multiple of 4."); 130 | exit(1); 131 | } 132 | long double sum1 = 0.0, sum2 = 0.0, sum3 = 0.0, xi = ig->lowerBound; 133 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 134 | sum2 += parse(&ig->expr, variable, xi += ig->dx); 135 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 136 | unsigned int i; 137 | for(i=4;iexpr, variable, xi += ig->dx); 139 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 140 | sum2 += parse(&ig->expr, variable, xi += ig->dx); 141 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 142 | } 143 | return 2.0 * ig->dx * (7.0*(parse(&ig->expr, variable, ig->lowerBound) + parse(&ig->expr, variable, ig->upperBound)) + 32.0*sum1 + 12.0*sum2 + 14.0*sum3) / 45.0; 144 | } 145 | 146 | // calculates the definite integral according to the Milne's rule 147 | long double milnesRule(Integral *ig, const unsigned int n, const char variable) { 148 | if(n%4) { 149 | puts("\nInvalid partition for Milne's Rule.\nn (number of intervals) must be a multiple of 4."); 150 | exit(1); 151 | } 152 | long double sum1 = 0.0, sum2 = 0.0, xi = ig->lowerBound; 153 | unsigned int i; 154 | for(i=1;iexpr, variable, xi += ig->dx); 156 | sum2 += parse(&ig->expr, variable, xi += ig->dx); 157 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 158 | xi += ig->dx; 159 | } 160 | return 4.0 * ig->dx * (2.0*sum1 - sum2) / 3.0; 161 | } 162 | 163 | // calculates the definite integral according to the Weddle's rule 164 | long double weddlesRule(Integral *ig, const unsigned int n, const char variable) { 165 | if(n%6) { 166 | puts("\nInvalid partition for Weddle's Rule.\nn (number of intervals) must be a multiple of 6."); 167 | exit(1); 168 | } 169 | long double sum1 = 0.0, sum2 = 0.0, sum3 = 0.0, sum4 = 0.0, xi = ig->lowerBound; 170 | sum2 += parse(&ig->expr, variable, xi += ig->dx); 171 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 172 | sum3 += parse(&ig->expr, variable, xi += ig->dx); 173 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 174 | sum2 += parse(&ig->expr, variable, xi += ig->dx); 175 | unsigned int i; 176 | for(i=6;iexpr, variable, xi += ig->dx); 178 | sum2 += parse(&ig->expr, variable, xi += ig->dx); 179 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 180 | sum3 += parse(&ig->expr, variable, xi += ig->dx); 181 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 182 | sum2 += parse(&ig->expr, variable, xi += ig->dx); 183 | } 184 | return 0.30 * ig->dx * (parse(&ig->expr, variable, ig->lowerBound) + parse(&ig->expr, variable, ig->upperBound) + sum1 + 5.0*sum2 + 6.0*sum3 + 2.0*sum4); 185 | } 186 | 187 | // calculates the definite integral according to the six point rule of closed type 188 | long double sixPointClosedRule(Integral *ig, const unsigned int n, const char variable) { 189 | if(n%5) { 190 | puts("\nInvalid partition for 6-Point Closed Rule.\nn (number of intervals) must be a multiple of 5."); 191 | exit(1); 192 | } 193 | long double sum1 = 0.0, sum2 = 0.0, sum3 = 0.0, xi = ig->lowerBound; 194 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 195 | sum2 += parse(&ig->expr, variable, xi += ig->dx); 196 | sum2 += parse(&ig->expr, variable, xi += ig->dx); 197 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 198 | unsigned int i; 199 | for(i=5;iexpr, variable, xi += ig->dx); 201 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 202 | sum2 += parse(&ig->expr, variable, xi += ig->dx); 203 | sum2 += parse(&ig->expr, variable, xi += ig->dx); 204 | sum1 += parse(&ig->expr, variable, xi += ig->dx); 205 | } 206 | return 5.0 * ig->dx * (19.0*(parse(&ig->expr, variable, ig->lowerBound) + parse(&ig->expr, variable, ig->upperBound)) + 75.0*sum1 + 50.0*sum2 + 38.0*sum3) / 288.0; 207 | } 208 | 209 | #endif 210 | -------------------------------------------------------------------------------- /Header/calculator.h: -------------------------------------------------------------------------------- 1 | #ifndef _CALCULATOR_H_ 2 | #define _CALCULATOR_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define TRUE 1 11 | #define FALSE 0 12 | #define MAX_EXPRESSION_LENGTH 300 13 | 14 | // header which contains methods to parse and calculate the string expression 15 | 16 | // expression struct declaration 17 | typedef struct { 18 | char expression[MAX_EXPRESSION_LENGTH], currentChar; 19 | unsigned int currentPos; 20 | unsigned short anglesAreDegrees; 21 | } Expression; 22 | 23 | // function declarations 24 | long double factorial(const long double x); 25 | void removeChar(char *str, const char charToRemove); 26 | void putCharToString(char* str, const char charToPut, const unsigned int index); 27 | char* getSubstring(char* str, const unsigned int beginPos, const unsigned int endPos); 28 | void getNextChar(Expression *expr); 29 | unsigned short eat(Expression *expr, const char charToEat); 30 | long double parse(Expression *expr, const char variable, const long double value); 31 | long double parseExpression(Expression *expr, const char variable, const long double value); 32 | long double parseTerm(Expression *expr, const char variable, const long double value); 33 | long double parseTerm2(Expression *expr, const char variable, const long double value); 34 | long double parseTerm3(Expression *expr, const char variable, const long double value); 35 | long double parseTerm4(Expression *expr, const char variable, const long double value); 36 | long double parseFactor(Expression *expr, const char variable, const long double value); 37 | 38 | 39 | // returns the factorial of x 40 | long double factorial(const long double x) { 41 | if(x != (long double)(long long)x || x < 0.0) { 42 | __mingw_printf("\nInvalid factorial: \"%Lg!\"\nCan't take factorial of %s numbers.\n", x, x<0 ? "negative" : "non-integer"); 43 | exit(1); 44 | } 45 | unsigned short i; 46 | long double res = 1.0; 47 | for(i=2; i<=x; res*=i, i++); 48 | return res; 49 | } 50 | 51 | // removes all the occurrences of "charToRemove" in the given string 52 | void removeChar(char *str, const char charToRemove) { 53 | char *src, *dst; 54 | for(src=dst=str; *src; src++) 55 | if((*dst = *src) != charToRemove) 56 | dst++; 57 | *dst = '\0'; 58 | } 59 | 60 | // inserts a character onto the specified index in the given string 61 | void putCharToString(char* str, const char charToPut, const unsigned int index) { 62 | unsigned int i; 63 | for(i=strlen(str);i>=index;i--) 64 | str[i+1] = str[i]; 65 | str[index] = charToPut; 66 | } 67 | 68 | // returns a substring of the given string 69 | char* getSubstring(char* str, const unsigned int beginPos, const unsigned int endPos) { 70 | if(beginPos >= endPos) { 71 | puts("\nWrong parameters for substring function."); 72 | exit(1); 73 | } 74 | char* subStr = (char*) malloc((endPos - beginPos + 1) * sizeof(char)); 75 | memcpy(subStr, &str[beginPos], endPos - beginPos); 76 | subStr[endPos - beginPos] = '\0'; 77 | return subStr; 78 | } 79 | 80 | // gets the next character given in expression 81 | void getNextChar(Expression *expr) { 82 | expr->currentChar = expr->expression[++expr->currentPos]; 83 | } 84 | 85 | // returns true if the current character is "charToEat" and progresses to the next character, false otherwise 86 | unsigned short eat(Expression *expr, const char charToEat) { 87 | if(expr->currentChar == charToEat) { 88 | getNextChar(expr); 89 | return TRUE; 90 | } 91 | return FALSE; 92 | } 93 | 94 | // main function which parses and calculates the expression and returns the calculated result of the expression 95 | long double parse(Expression *expr, const char variable, const long double value) { 96 | removeChar(expr->expression, ' '); 97 | unsigned int i; 98 | for(i=0;expr->expression[i];i++) 99 | if((expr->expression[i] >= '0' && expr->expression[i] <= '9') || expr->expression[i] == ')') 100 | if((expr->expression[i+1] >= 'a' && expr->expression[i+1] <= 'z') || expr->expression[i+1] == '(') // add a multiplication sign if not specified 101 | putCharToString(expr->expression, '*', i+1); // e.g., 2(5x+3) => 2*(5*x+3) 102 | const long double x = parseExpression(expr, variable, value); 103 | if(expr->currentPos < strlen(expr->expression)) { 104 | printf("\nUnexpected character: '%c'\n", expr->currentChar); 105 | exit(1); 106 | } 107 | expr->currentPos = 0; 108 | expr->currentChar = expr->expression[0]; 109 | return x; 110 | } 111 | 112 | // parses the expression to terms according to addition and substraction 113 | long double parseExpression(Expression *expr, const char variable, const long double value) { 114 | long double x = parseTerm(expr, variable, value); 115 | while(TRUE) 116 | if(eat(expr, '+')) 117 | x += parseTerm(expr, variable, value); // addition 118 | else if(eat(expr, '-')) 119 | x -= parseTerm(expr, variable, value); // substraction 120 | else 121 | return x; 122 | } 123 | 124 | // parses the terms of the expression according to multiplication and division 125 | long double parseTerm(Expression *expr, const char variable, const long double value) { 126 | long double x = parseTerm2(expr, variable, value); 127 | while(TRUE) 128 | if(eat(expr, '*')) 129 | x *= parseTerm2(expr, variable, value); // multiplication 130 | else if(eat(expr, '/')) { 131 | const long double temp = parseTerm2(expr, variable, value); 132 | if(!temp) { 133 | __mingw_printf("\nInvalid division: \"%Lg/0\"\nCan't divide by zero.\n", x); 134 | exit(1); 135 | } 136 | x /= temp; // division 137 | } 138 | else 139 | return x; 140 | } 141 | 142 | // parses the terms of the expression according to modulo operation 143 | long double parseTerm2(Expression *expr, const char variable, const long double value) { 144 | long double x = parseTerm3(expr, variable, value); 145 | while(TRUE) 146 | if(eat(expr, '%')) { 147 | const long double temp = parseTerm3(expr, variable, value); 148 | if(!temp) { 149 | __mingw_printf("\nInvalid modulo: \"%Lg%%0\"\nModulus can't be zero.\n", x); 150 | exit(1); 151 | } 152 | x = fmod((temp + fmod(x, temp)), temp); // modulo operation 153 | } 154 | else 155 | return x; 156 | } 157 | 158 | // parses the terms of the expression according to exponentiation 159 | long double parseTerm3(Expression *expr, const char variable, const long double value) { 160 | long double x = parseTerm4(expr, variable, value); 161 | while(TRUE) 162 | if(eat(expr, '^')) 163 | x = pow(x, parseTerm4(expr, variable, value)); // exponentiation 164 | else 165 | return x; 166 | } 167 | 168 | // parses the terms of the expression according to factorial 169 | long double parseTerm4(Expression *expr, const char variable, const long double value) { 170 | long double x = parseFactor(expr, variable, value); 171 | while(TRUE) 172 | if(eat(expr, '!')) 173 | x = factorial(x); // factorial 174 | else 175 | return x; 176 | } 177 | 178 | // parses the factors of the terms according to various elements such as parantheses, numbers, functions, constants, etc. 179 | long double parseFactor(Expression *expr, const char variable, const long double value) { 180 | if(eat(expr, '+')) 181 | return parseFactor(expr, variable, value); //positive numbers 182 | if(eat(expr, '-')) 183 | return -parseFactor(expr, variable, value); //negative numbers 184 | long double x; 185 | const unsigned int startPos = expr->currentPos; 186 | if(eat(expr, '(')) { // parantheses 187 | x = parseExpression(expr, variable, value); 188 | eat(expr, ')'); 189 | } 190 | else if((expr->currentChar >= '0' && expr->currentChar <= '9') || expr->currentChar == '.') { // numbers 191 | while((expr->currentChar >= '0' && expr->currentChar <= '9') || expr->currentChar == '.') 192 | getNextChar(expr); 193 | x = atof(getSubstring(expr->expression, startPos, expr->currentPos)); 194 | } 195 | else if(expr->currentChar >= 'a' && expr->currentChar <= 'z') { // functions and constants 196 | while(expr->currentChar >= 'a' && expr->currentChar <= 'z') 197 | getNextChar(expr); 198 | char* func = getSubstring(expr->expression, startPos, expr->currentPos); 199 | if(!strcmp(func, (char[]){variable, '\0'})) return value; 200 | if(!strcmp(func, "e")) return M_E; // Euler's number, pi and infinity 201 | if(!strncmp(func, "pi", 2)) return M_PI; 202 | if(!strncmp(func, "inf", 3)) return LDBL_MAX; 203 | x = parseFactor(expr, variable, value); 204 | if(!strncmp(func,"sqrt", 4)) { // root (square root and cubic root) 205 | if(x < 0.0) { 206 | __mingw_printf("\nInvalid square root: \"sqrt(%Lg)\"\nCan't take square root of negative numbers.\n", x); 207 | exit(1); 208 | } 209 | x = sqrt(x); 210 | } 211 | else if(!strncmp(func, "cbrt", 4)) x = cbrt(x); 212 | else if(!strncmp(func, "sqr", 3)) x *= x; // exponentiation (square and cube) 213 | else if(!strncmp(func, "cube", 4)) x *= x*x; 214 | else if(!strncmp(func, "abs", 3)) x = fabs(x); // absolute value 215 | else if(!strncmp(func, "ceil", 4)) x = ceil(x); // rounding 216 | else if(!strncmp(func, "floor", 5)) x = floor(x); 217 | else if(!strncmp(func, "round", 5)) x = round(x); 218 | else if(!strncmp(func, "fact", 4)) x = factorial(x); // factorial 219 | else if(!strncmp(func, "sinh", 4)) x = sinh(x); // hyperbolic trigonometric functions 220 | else if(!strncmp(func, "cosh", 4)) x = cosh(x); 221 | else if(!strncmp(func, "tanh", 4)) x = tanh(x); 222 | else if(!strncmp(func, "coth", 4)) { 223 | if(!x) { 224 | puts("\nInvalid hyperbolic cotangent: \"coth(0)\"\nHyperbolic cotangent of zero doesn't exist."); 225 | exit(1); 226 | } 227 | x = 1.0 / tanh(x); 228 | } 229 | else if(!strncmp(func, "sech", 4)) 230 | x = 1.0 / cosh(x); 231 | else if(!strncmp(func, "csch", 4)) { 232 | if(!x) { 233 | puts("\nInvalid hyperbolic cosecant: \"csch(0)\"\nHyperbolic cosecant of zero doesn't exist."); 234 | exit(1); 235 | } 236 | x = 1.0 / sinh(x); 237 | } 238 | else if(!strncmp(func, "sec", 3)) { 239 | if(expr->anglesAreDegrees) 240 | x *= M_PI / 180.0; 241 | if(fmod(x, M_PI) == M_PI/2.0) { 242 | __mingw_printf("\nInvalid secant: \"sec(%Lg)\"\nCan't take secant of angles that are %s in which k is an integer.\n", x, expr->anglesAreDegrees ? "90+180*k degrees" : "pi/2+pi*k radians"); 243 | exit(1); 244 | } 245 | x = 1.0 / cos(x); 246 | } 247 | else if(!strncmp(func, "csc", 3) || !strncmp(func, "cosec", 5)) { 248 | if(expr->anglesAreDegrees) 249 | x *= M_PI / 180.0; 250 | if(!fmod(x, M_PI)) { 251 | __mingw_printf("\nInvalid cosecant: \"csc(%Lg)\"\nCan't take cosecant of angles that are %s in which k is an integer.\n", x, expr->anglesAreDegrees ? "180*k degrees" : "pi*k radians"); 252 | exit(1); 253 | } 254 | x = 1.0 / sin(x); 255 | } 256 | else if(!strncmp(func, "sin", 3)) { // trigonometric functions 257 | if(expr->anglesAreDegrees) 258 | x *= M_PI / 180.0; 259 | x = fmod(x, M_PI) ? sin(x) : 0.0; 260 | } 261 | else if(!strncmp(func, "cos", 3)) { 262 | if(expr->anglesAreDegrees) 263 | x *= M_PI / 180.0; 264 | x = fmod(x, M_PI) == M_PI/2.0 ? 0.0 : cos(x); 265 | } 266 | else if(!strncmp(func, "tan", 3)) { 267 | if(expr->anglesAreDegrees) 268 | x *= M_PI / 180.0; 269 | if(fmod(x, M_PI) == M_PI/2.0) { 270 | __mingw_printf("\nInvalid tangent: \"tan(%Lg)\"\nCan't take tangent of angles that are %s in which k is an integer.\n", x, expr->anglesAreDegrees ? "90+180*k degrees" : "pi/2+pi*k radians"); 271 | exit(1); 272 | } 273 | x = fmod(x, M_PI) ? tan(x) : 0.0; 274 | } 275 | else if(!strncmp(func, "cot", 3)) { 276 | if(expr->anglesAreDegrees) 277 | x *= M_PI / 180.0; 278 | if(!fmod(x, M_PI)) { 279 | __mingw_printf("\nInvalid cotangent: \"cot(%Lg)\"\nCan't take cotangent of angles that are %s in which k is an integer.\n", x, expr->anglesAreDegrees ? "180*k degrees" : "pi*k radians"); 280 | exit(1); 281 | } 282 | x = fmod(x, M_PI) == M_PI/2.0 ? 0.0 : 1.0 / tan(x); 283 | } 284 | else if(!strncmp(func,"asin",4) || !strncmp(func, "arcsin", 6)) { // inverse trigonometric functions 285 | if(x < -1.0 || x > 1.0) { 286 | __mingw_printf("\nInvalid arcsine: \"asin(%Lg)\"\nArcsine of numbers less than -1 or greater than 1 doesn't exist.\n", x); 287 | exit(1); 288 | } 289 | x = asin(x); 290 | if(expr->anglesAreDegrees) 291 | x *= 180.0 / M_PI; 292 | } 293 | else if(!strncmp(func, "acos", 4) || !strncmp(func, "arccos", 6)) { 294 | if(x < -1.0 || x > 1.0) { 295 | __mingw_printf("\nInvalid arccosine: \"acos(%Lg)\"\nArccosine of numbers less than -1 or greater than 1 doesn't exist.\n", x); 296 | exit(1); 297 | } 298 | x = acos(x); 299 | if(expr->anglesAreDegrees) 300 | x *= 180.0 / M_PI; 301 | } 302 | else if(!strncmp(func, "atan", 4) || !strncmp(func, "arctan", 6)) { 303 | x = atan(x); 304 | if(expr->anglesAreDegrees) 305 | x *= 180.0 / M_PI; 306 | } 307 | else if(!strncmp(func, "acot", 4) || !strncmp(func, "arccot", 6)) { 308 | x = atan(1.0 / x); 309 | if(expr->anglesAreDegrees) 310 | x *= 180.0 / M_PI; 311 | } 312 | else if(!strncmp(func, "asec", 4) || !strncmp(func, "arcsec", 6)) { 313 | if(-1.0 < x && x < 1.0) { 314 | __mingw_printf("\nInvalid arcsecant: \"asec(%Lg)\"\nArcsecant of numbers between -1 and 1 doesn't exist.\n", x); 315 | exit(1); 316 | } 317 | x = acos(1.0 / x); 318 | if(expr->anglesAreDegrees) 319 | x *= 180.0 / M_PI; 320 | } 321 | else if(!strncmp(func, "acsc", 4) || !strncmp(func, "arccsc", 6)) { 322 | if(-1.0 < x && x < 1.0) { 323 | __mingw_printf("\nInvalid arccosecant: \"acsc(%Lg)\"\nArccosecant of numbers between -1 and 1 doesn't exist.\n", x); 324 | exit(1); 325 | } 326 | x = asin(1.0 / x); 327 | if(expr->anglesAreDegrees) 328 | x *= 180.0 / M_PI; 329 | } 330 | else if(!strncmp(func, "ln", 2)) { // logarithm 331 | if(x <= 0.0) { 332 | __mingw_printf("\nInvalid logarithm: \"ln(%Lg)\"\nCan't take logarithm of non-positive numbers.\n", x); 333 | exit(1); 334 | } 335 | x = log(x); 336 | } 337 | else if(!strncmp(func, "log", 3)) { 338 | if(x <= 0.0) { 339 | __mingw_printf("\nInvalid logarithm: \"log(%Lg)\"\nCan't take logarithm of non-positive numbers.\n", x); 340 | exit(1); 341 | } 342 | x = log10(x); 343 | } 344 | else if(!strncmp(func, "exp", 3)) // e^x 345 | x = exp(x); 346 | else { 347 | printf("\nUnknown function: \"%s\"\n", func); 348 | exit(1); 349 | } 350 | } 351 | else { // reached an unidentified character 352 | printf("\nUnexpected character: '%c'\n", expr->currentChar); 353 | exit(1); 354 | } 355 | return x; 356 | } 357 | 358 | #endif 359 | --------------------------------------------------------------------------------