]>
jfr.im git - irc/evilnet/x3.git/blob - src/math.c
1 /* math.c - Mathematics functions for chanserv.calc
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version. Important limitations are
7 * listed in the COPYING file that accompanies this software.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, email srvx-maintainers@srvx.net.
34 #define strcasecmp stricmp
69 /* This table is needed for the translation from infix to postfix. */
70 static const int TranslateTable
[][10] = {
71 /*List: _ + - * / ^ ( ) [ ] */
73 /* _ */ {4, 1, 1, 1, 1, 1, 1, 5, 1, 5},
74 /* + */ {2, 2, 2, 1, 1, 1, 1, 2, 1, 2},
75 {2, 2, 2, 1, 1, 1, 1, 2, 1, 2},
76 {2, 2, 2, 2, 2, 1, 1, 2, 1, 2},
77 {2, 2, 2, 2, 2, 1, 1, 2, 1, 2},
78 {2, 2, 2, 2, 2, 2, 1, 2, 1, 2},
79 {5, 1, 1, 1, 1, 1, 1, 3, 1, 5},
80 {5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
81 {5, 1, 1, 1, 1, 1, 1, 5, 1, 6},
82 {5, 5, 5, 5, 5, 5, 5, 5, 5, 5}
85 typedef struct MathToken
{
88 enum MathOpType OpType
;
89 struct MathToken
*Next
;
90 struct MathToken
*Previous
; /* Previous is used in the stack */
93 typedef struct Values
{
96 struct Values
*Previous
;
99 void do_math(char *Buffer
, char *Math
)
103 double Floating
; /* = 10^number of digits after the dot */
104 int ValueExpected
= 1;
105 char Identifier
[512];
107 MathList ListFirst
= NULL
;
108 MathList StackFirst
= NULL
;
109 MathList PostFixFirst
= NULL
;
110 ValueList TheValuesFirst
= NULL
;
121 if (!(List
= ListFirst
= malloc(sizeof(struct MathToken
)))) goto MemError
;
122 if (!(Stack
= StackFirst
= malloc(sizeof(struct MathToken
)))) goto MemError
;
123 if (!(PostFix
= PostFixFirst
= malloc(sizeof(struct MathToken
)))) goto MemError
;
124 if (!(TheValues
= TheValuesFirst
= malloc(sizeof(struct Values
)))) goto MemError
;
128 PostFix
->Next
= NULL
;
129 TheValues
->Next
= NULL
;
131 StackFirst
->Type
= mEnd
;
133 /* First tokenize the buffer */
136 if (isdigit(*Math
) || *Math
== '.') {
137 if (!ValueExpected
) {
138 strcpy(Buffer
, "Unexpected value");
144 while (isdigit(*Math
) || *Math
== '.') {
147 strcpy(Buffer
, "Error in constant");
154 Value
= Value
* 10 + *Math
- '0';
156 Floating
= Floating
* 10;
157 Value
= Value
+ (*Math
- '0') / Floating
;
161 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
163 List
->Type
= mNumber
;
166 List
->Value
= -Value
;
171 else switch (*Math
) {
179 if (*Math
== '-' && ValueExpected
) {
184 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto End
;
187 case '+': List
->Type
= mPlus
; break;
188 case '-': List
->Type
= mMinus
; break;
189 case '*': List
->Type
= mMult
; break;
190 case '/': List
->Type
= mDiv
; break;
191 case '^': List
->Type
= mPower
; break;
192 case '(': List
->Type
= mLt
; break;
193 case ')': List
->Type
= mRt
; break;
194 case ']': List
->Type
= mOpEnd
; break;
196 if (*Math
!= '(' && ValueExpected
) {
197 strcpy(Buffer
, "Value expected");
200 if (*Math
!= ')' && *Math
!= ']')
205 if (isalpha(*Math
)) {
207 while (isalpha(*Math
))
208 Identifier
[Index
++] = *Math
++;
209 Identifier
[Index
] = '\0';
211 if (!ValueExpected
) {
212 strcpy(Buffer
, "Unexpected value");
215 if (!strcasecmp(Identifier
, "e")) {
216 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
218 List
->Type
= mNumber
;
219 List
->Value
= exp(1);
222 else if (!strcasecmp(Identifier
, "pi")) {
223 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
225 List
->Type
= mNumber
;
226 List
->Value
= 4 * atan(1);
229 else if (!strcasecmp(Identifier
, "rand")) {
230 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
232 List
->Type
= mNumber
;
233 List
->Value
= (double)rand() / (double)RAND_MAX
;
236 else if (!strcasecmp(Identifier
, "exp")) {
237 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
240 List
->OpType
= otExp
;
243 else if (!strcasecmp(Identifier
, "log")) {
244 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
247 List
->OpType
= otLog
;
250 else if (!strcasecmp(Identifier
, "sin")) {
251 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
254 List
->OpType
= otSin
;
257 else if (!strcasecmp(Identifier
, "asin")) {
258 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
261 List
->OpType
= otASin
;
264 else if (!strcasecmp(Identifier
, "sinh")) {
265 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
268 List
->OpType
= otSinH
;
271 else if (!strcasecmp(Identifier
, "cos")) {
272 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
275 List
->OpType
= otCos
;
278 else if (!strcasecmp(Identifier
, "acos")) {
279 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
282 List
->OpType
= otACos
;
285 else if (!strcasecmp(Identifier
, "cosh")) {
286 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
289 List
->OpType
= otCosH
;
292 else if (!strcasecmp(Identifier
, "tan")) {
293 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
296 List
->OpType
= otTan
;
299 else if (!strcasecmp(Identifier
, "atan")) {
300 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
303 List
->OpType
= otATan
;
306 else if (!strcasecmp(Identifier
, "tanh")) {
307 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
310 List
->OpType
= otTanH
;
313 else if (!strcasecmp(Identifier
, "sqrt")) {
314 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
317 List
->OpType
= otSqrt
;
320 else if (!strcasecmp(Identifier
, "abs")) {
321 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
324 List
->OpType
= otAbs
;
327 else if (!strcasecmp(Identifier
, "ceil")) {
328 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
331 List
->OpType
= otCeil
;
334 else if (!strcasecmp(Identifier
, "floor")) {
335 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
338 List
->OpType
= otFloor
;
342 strcpy(Buffer
, "Unexpected Identifier");
346 while (*Math
== ' ' || *Math
== '\t')
349 strcpy(Buffer
, "'[' expected");
356 strcpy(Buffer
, "Unknown character in expression");
362 strcpy(Buffer
, "Value expected");
365 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
369 /* We've got them tokenized now... now convert it
370 from infix notation to postfix notation */
372 List
= ListFirst
->Next
;
374 if (List
->Type
== mNumber
) {
375 PostFix
= PostFix
->Next
= List
;
376 ListFirst
= List
= List
->Next
;
377 PostFix
->Next
= NULL
;
379 else switch (TranslateTable
[Stack
->Type
][List
->Type
]) {
381 List
->Previous
= Stack
;
382 Stack
= Stack
->Next
= List
;
383 ListFirst
= List
= List
->Next
;
387 PostFix
= PostFix
->Next
= Stack
;
388 Stack
= Stack
->Previous
;
392 Stack
= Stack
->Previous
;
396 ListFirst
= List
= List
->Next
;
400 PostFix
= PostFix
->Next
= List
;
401 ListFirst
= List
= List
->Next
;
404 strcpy(Buffer
, "Error in expression");
407 PostFix
= PostFix
->Next
= Stack
;
408 Stack
= Stack
->Previous
;
411 ListFirst
= List
= List
->Next
;
415 strcpy(Buffer
, "Internal error");
420 /* Now we've got everything in Postfix notation... calculate it now */
422 PostFix
= PostFixFirst
->Next
;
424 switch (PostFix
->Type
) {
426 if (!(TheValues
->Next
= malloc(sizeof(struct Values
)))) goto MemError
;
427 TheValues
->Next
->Previous
= TheValues
;
428 TheValues
= TheValues
->Next
;
429 TheValues
->Next
= NULL
;
430 TheValues
->Value
= PostFix
->Value
;
433 TheValues
->Previous
->Value
+= TheValues
->Value
;
434 TheValues
= TheValues
->Previous
;
435 free(TheValues
->Next
);
436 TheValues
->Next
= NULL
;
439 TheValues
->Previous
->Value
-= TheValues
->Value
;
440 TheValues
= TheValues
->Previous
;
441 free(TheValues
->Next
);
442 TheValues
->Next
= NULL
;
445 TheValues
->Previous
->Value
*= TheValues
->Value
;
446 TheValues
= TheValues
->Previous
;
447 free(TheValues
->Next
);
448 TheValues
->Next
= NULL
;
451 if (TheValues
->Value
== 0) {
452 strcpy(Buffer
, "Division by zero error!");
455 TheValues
->Previous
->Value
/= TheValues
->Value
;
456 TheValues
= TheValues
->Previous
;
457 free(TheValues
->Next
);
458 TheValues
->Next
= NULL
;
461 TheValues
->Previous
->Value
= pow(TheValues
->Previous
->Value
, TheValues
->Value
);
462 TheValues
= TheValues
->Previous
;
463 free(TheValues
->Next
);
464 TheValues
->Next
= NULL
;
467 Value
= TheValues
->Value
;
470 switch (PostFix
->OpType
) {
472 TheValues
->Value
= exp(TheValues
->Value
);
475 if (TheValues
->Value
<= 0) {
476 strcpy(Buffer
, "Log of non-positive value error");
479 TheValues
->Value
= log(TheValues
->Value
);
482 TheValues
->Value
= sin(TheValues
->Value
);
485 if (TheValues
->Value
< -1 || TheValues
->Value
> 1) {
486 strcpy(Buffer
, "Domain error");
489 TheValues
->Value
= asin(TheValues
->Value
);
492 TheValues
->Value
= sinh(TheValues
->Value
);
494 TheValues
->Value
= cos(TheValues
->Value
);
497 if (TheValues
->Value
< -1 || TheValues
->Value
> 1) {
498 strcpy(Buffer
, "Domain error");
501 TheValues
->Value
= acos(TheValues
->Value
);
504 TheValues
->Value
= cosh(TheValues
->Value
);
507 TheValues
->Value
= tan(TheValues
->Value
);
510 TheValues
->Value
= atan(TheValues
->Value
);
513 TheValues
->Value
= tanh(TheValues
->Value
);
516 if (TheValues
->Value
< 0) {
517 strcpy(Buffer
, "Sqrt from number < 0");
520 TheValues
->Value
= sqrt(TheValues
->Value
);
523 TheValues
->Value
= fabs(TheValues
->Value
);
526 TheValues
->Value
= ceil(TheValues
->Value
);
529 TheValues
->Value
= floor(TheValues
->Value
);
533 /* The following three do not occur. They are here to prevent compiler warnings */
539 PostFix
= PostFix
->Next
;
542 if (fabs(Value
) < 1000000 && (fabs(Value
) > 0.001 || Value
== 0.0))
544 if (fabs(Value
- floor(Value
+ 0.5)) < 0.00001) {
545 sprintf(Buffer
, "%.0f", Value
);
548 sprintf(Buffer
, "%f", Value
);
552 sprintf(Buffer
, "%E", Value
);
555 /* Free up memory here */
571 PostFix
= PostFixFirst
;
574 PostFix
= PostFix
->Next
;
578 TheValues
= TheValuesFirst
;
581 TheValues
= TheValues
->Next
;
588 strcpy(Buffer
, "Couldn't allocate enough memory");