]> jfr.im git - irc/evilnet/x3.git/blob - src/math.c
Fixes for a few compiler warnings and errors
[irc/evilnet/x3.git] / src / math.c
1 /* math.c - Mathematics functions for chanserv.calc
2 *
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 3 of the License, or
6 * (at your option) any later version. Important limitations are
7 * listed in the COPYING file that accompanies this software.
8 *
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.
13 *
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.
16 *
17 * $Id$
18 */
19
20 #include "conf.h"
21 #include "helpfile.h"
22 #include "nickserv.h"
23 #include "modcmd.h"
24 #include "saxdb.h"
25 #include "timeq.h"
26
27 #ifdef HAVE_MATH_H
28 #include <math.h>
29 #include <complex.h>
30 #else
31 #include <tgmath.h>
32 #endif
33
34 #include <ctype.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <time.h>
39
40 #ifdef WIN32
41 #define strcasecmp stricmp
42 #endif
43
44 enum MathType {
45 mEnd,
46 mPlus,
47 mMinus,
48 mMult,
49 mDiv,
50 mPower,
51 mLt,
52 mRt,
53 mOp,
54 mOpEnd,
55 mNumber
56 };
57
58 enum MathOpType {
59 otExp,
60 otLog,
61 otSin,
62 otASin,
63 otSinH,
64 otCos,
65 otACos,
66 otCosH,
67 otTan,
68 otATan,
69 otTanH,
70 otSqrt,
71 otAbs,
72 otCeil,
73 otFloor
74 };
75
76 /* This table is needed for the translation from infix to postfix. */
77 static const int TranslateTable[][10] = {
78 /*List: _ + - * / ^ ( ) [ ] */
79 /*Stack: */
80 /* _ */ {4, 1, 1, 1, 1, 1, 1, 5, 1, 5},
81 /* + */ {2, 2, 2, 1, 1, 1, 1, 2, 1, 2},
82 {2, 2, 2, 1, 1, 1, 1, 2, 1, 2},
83 {2, 2, 2, 2, 2, 1, 1, 2, 1, 2},
84 {2, 2, 2, 2, 2, 1, 1, 2, 1, 2},
85 {2, 2, 2, 2, 2, 2, 1, 2, 1, 2},
86 {5, 1, 1, 1, 1, 1, 1, 3, 1, 5},
87 {5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
88 {5, 1, 1, 1, 1, 1, 1, 5, 1, 6},
89 {5, 5, 5, 5, 5, 5, 5, 5, 5, 5}
90 };
91
92 typedef struct MathToken {
93 enum MathType Type;
94 double Value;
95 enum MathOpType OpType;
96 struct MathToken *Next;
97 struct MathToken *Previous; /* Previous is used in the stack */
98 } *MathList;
99
100 typedef struct Values {
101 double Value;
102 struct Values *Next;
103 struct Values *Previous;
104 } *ValueList;
105
106 void do_math(char *Buffer, char *Math)
107 {
108 int HasDot;
109 double Value = 0.0;
110 double Floating; /* = 10^number of digits after the dot */
111 int ValueExpected = 1;
112 char Identifier[512];
113
114 MathList ListFirst = NULL;
115 MathList StackFirst = NULL;
116 MathList PostFixFirst = NULL;
117 ValueList TheValuesFirst = NULL;
118 MathList List;
119 MathList Stack;
120 MathList PostFix;
121 ValueList TheValues;
122 int Minus = 0;
123
124 void *Temp;
125 int Index;
126 int OEndExpected;
127
128
129 /* This is a HACK to insert * before ( so multiplication takes place
130 * in things such as 3(3) instead of ignoring the first 3. Submitted
131 * by Osiris.
132 * I spent some time tlooking at calc.c and I didnt see an easy way
133 * to do this there... and that file gives me a headache.. so.. -Rubin
134 */
135 char newMath[MAXLEN];
136 char *ptr;
137 char lastNumber = false;
138 char lastBracket = false;
139
140
141 ptr = newMath;
142 while(*Math && ptr < newMath+MAXLEN-1)
143 {
144 switch(*Math)
145 {
146 case '1': case '2':
147 case '3': case '4':
148 case '5': case '6':
149 case '7': case '8':
150 case '9': case '0':
151 lastNumber = true;
152 if(lastBracket == true)
153 {
154 *ptr = '*';
155 ptr++;
156 }
157 *ptr = *Math;
158 lastBracket = false;
159 break;
160 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
161 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
162 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
163 case 'v': case 'w': case 'x': case 'y': case 'z':
164 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
165 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
166 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
167 case 'V': case 'W': case 'X': case 'Y': case 'Z':
168 case ')': case ']': /* Support sin[12](3) also */
169 lastNumber = true;
170 lastBracket = true;
171 *ptr = *Math;
172 break;
173 case '(': case '[':
174 if (lastNumber == true)
175 {
176 *ptr = '*';
177 ptr++;
178 }
179 *ptr = *Math;
180 lastNumber = false;
181 lastBracket = false;
182 break;
183 default:
184 if(isalpha(*Math))
185 {
186 if(lastNumber == true)
187 {
188 *ptr = '*';
189 ptr++;
190 }
191 }
192 *ptr = *Math;
193 lastNumber = false;
194 lastBracket = false;
195 break;
196 }
197 Math++;
198 ptr++;
199 }
200 *ptr = '\0';
201 Math = newMath;
202
203 if (!(List = ListFirst = malloc(sizeof(struct MathToken)))) goto MemError;
204 if (!(Stack = StackFirst = malloc(sizeof(struct MathToken)))) goto MemError;
205 if (!(PostFix = PostFixFirst = malloc(sizeof(struct MathToken)))) goto MemError;
206 if (!(TheValues = TheValuesFirst = malloc(sizeof(struct Values)))) goto MemError;
207
208 List->Next = NULL;
209 Stack->Next = NULL;
210 PostFix->Next = NULL;
211 TheValues->Next = NULL;
212
213 StackFirst->Type = mEnd;
214
215 /* First tokenize the buffer */
216
217 while (*Math) {
218 if (isdigit(*Math) || *Math == '.') {
219 if (!ValueExpected) {
220 strcpy(Buffer, "Unexpected value");
221 goto End;
222 }
223 HasDot = 0;
224 Value = 0;
225 Floating = 1;
226 while (isdigit(*Math) || *Math == '.') {
227 if (*Math == '.')
228 if (HasDot) {
229 strcpy(Buffer, "Error in constant");
230 goto End;
231 }
232 else
233 HasDot = 1;
234 else
235 if (!HasDot)
236 Value = Value * 10 + *Math - '0';
237 else {
238 Floating = Floating * 10;
239 Value = Value + (*Math - '0') / Floating;
240 }
241 ++Math;
242 }
243 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
244 List->Next = NULL;
245 List->Type = mNumber;
246 List->Value = Value;
247 if (Minus) {
248 List->Value = -Value;
249 Minus = 0;
250 }
251 ValueExpected = 0;
252 }
253 else switch (*Math) {
254 case ' ': case '\t':
255 ++Math;
256 break;
257 case '+': case '-':
258 case '*': case '/':
259 case '^': case '(':
260 case ')': case ']':
261 if (*Math == '-' && ValueExpected) {
262 Minus = !Minus;
263 ++Math;
264 break;
265 }
266 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto End;
267 List->Next = NULL;
268 switch (*Math) {
269 case '+': List->Type = mPlus; break;
270 case '-': List->Type = mMinus; break;
271 case '*': List->Type = mMult; break;
272 case '/': List->Type = mDiv; break;
273 case '^': List->Type = mPower; break;
274 case '(': List->Type = mLt; break;
275 case ')': List->Type = mRt; break;
276 case ']': List->Type = mOpEnd; break;
277 }
278 if (*Math != '(' && ValueExpected) {
279 strcpy(Buffer, "Value expected");
280 goto End;
281 }
282 if (*Math != ')' && *Math != ']')
283 ValueExpected = 1;
284 ++Math;
285 break;
286 default:
287 if (isalpha(*Math)) {
288 Index = 0;
289 while (isalpha(*Math))
290 Identifier[Index++] = *Math++;
291 Identifier[Index] = '\0';
292 OEndExpected = 0;
293 if (!ValueExpected) {
294 strcpy(Buffer, "Unexpected value");
295 goto End;
296 }
297 if (!strcasecmp(Identifier, "e")) {
298 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
299 List->Next = NULL;
300 List->Type = mNumber;
301 List->Value = exp(1);
302 ValueExpected = 0;
303 }
304 else if (!strcasecmp(Identifier, "pi")) {
305 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
306 List->Next = NULL;
307 List->Type = mNumber;
308 List->Value = 4 * atan(1);
309 ValueExpected = 0;
310 }
311 else if (!strcasecmp(Identifier, "rand")) {
312 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
313 List->Next = NULL;
314 List->Type = mNumber;
315 List->Value = (double)rand() / (double)RAND_MAX;
316 ValueExpected = 0;
317 }
318 else if (!strcasecmp(Identifier, "exp")) {
319 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
320 List->Next = NULL;
321 List->Type = mOp;
322 List->OpType = otExp;
323 OEndExpected = 1;
324 }
325 else if (!strcasecmp(Identifier, "log")) {
326 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
327 List->Next = NULL;
328 List->Type = mOp;
329 List->OpType = otLog;
330 OEndExpected = 1;
331 }
332 else if (!strcasecmp(Identifier, "sin")) {
333 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
334 List->Next = NULL;
335 List->Type = mOp;
336 List->OpType = otSin;
337 OEndExpected = 1;
338 }
339 else if (!strcasecmp(Identifier, "asin")) {
340 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
341 List->Next = NULL;
342 List->Type = mOp;
343 List->OpType = otASin;
344 OEndExpected = 1;
345 }
346 else if (!strcasecmp(Identifier, "sinh")) {
347 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
348 List->Next = NULL;
349 List->Type = mOp;
350 List->OpType = otSinH;
351 OEndExpected = 1;
352 }
353 else if (!strcasecmp(Identifier, "cos")) {
354 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
355 List->Next = NULL;
356 List->Type = mOp;
357 List->OpType = otCos;
358 OEndExpected = 1;
359 }
360 else if (!strcasecmp(Identifier, "acos")) {
361 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
362 List->Next = NULL;
363 List->Type = mOp;
364 List->OpType = otACos;
365 OEndExpected = 1;
366 }
367 else if (!strcasecmp(Identifier, "cosh")) {
368 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
369 List->Next = NULL;
370 List->Type = mOp;
371 List->OpType = otCosH;
372 OEndExpected = 1;
373 }
374 else if (!strcasecmp(Identifier, "tan")) {
375 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
376 List->Next = NULL;
377 List->Type = mOp;
378 List->OpType = otTan;
379 OEndExpected = 1;
380 }
381 else if (!strcasecmp(Identifier, "atan")) {
382 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
383 List->Next = NULL;
384 List->Type = mOp;
385 List->OpType = otATan;
386 OEndExpected = 1;
387 }
388 else if (!strcasecmp(Identifier, "tanh")) {
389 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
390 List->Next = NULL;
391 List->Type = mOp;
392 List->OpType = otTanH;
393 OEndExpected = 1;
394 }
395 else if (!strcasecmp(Identifier, "sqrt")) {
396 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
397 List->Next = NULL;
398 List->Type = mOp;
399 List->OpType = otSqrt;
400 OEndExpected = 1;
401 }
402 else if (!strcasecmp(Identifier, "abs")) {
403 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
404 List->Next = NULL;
405 List->Type = mOp;
406 List->OpType = otAbs;
407 OEndExpected = 1;
408 }
409 else if (!strcasecmp(Identifier, "ceil")) {
410 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
411 List->Next = NULL;
412 List->Type = mOp;
413 List->OpType = otCeil;
414 OEndExpected = 1;
415 }
416 else if (!strcasecmp(Identifier, "floor")) {
417 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
418 List->Next = NULL;
419 List->Type = mOp;
420 List->OpType = otFloor;
421 OEndExpected = 1;
422 }
423 else {
424 strcpy(Buffer, "Unexpected Identifier");
425 goto End;
426 }
427 if (OEndExpected) {
428 while (*Math == ' ' || *Math == '\t')
429 ++Math;
430 if (*Math != '[') {
431 strcpy(Buffer, "'[' expected");
432 goto End;
433 }
434 ++Math;
435 }
436 }
437 else {
438 strcpy(Buffer, "Unknown character in expression");
439 goto End;
440 }
441 }
442 }
443 if (ValueExpected) {
444 strcpy(Buffer, "Value expected");
445 goto End;
446 }
447 if (!(List = List->Next = malloc(sizeof(struct MathToken)))) goto MemError;
448 List->Next = NULL;
449 List->Type = mEnd;
450
451 /* We've got them tokenized now... now convert it
452 from infix notation to postfix notation */
453
454 List = ListFirst->Next;
455 while (List) {
456 if (List->Type == mNumber) {
457 PostFix = PostFix->Next = List;
458 ListFirst = List = List->Next;
459 PostFix->Next = NULL;
460 }
461 else switch (TranslateTable[Stack->Type][List->Type]) {
462 case 1:
463 List->Previous = Stack;
464 Stack = Stack->Next = List;
465 ListFirst = List = List->Next;
466 Stack->Next = NULL;
467 break;
468 case 2:
469 PostFix = PostFix->Next = Stack;
470 Stack = Stack->Previous;
471 Stack->Next = NULL;
472 break;
473 case 3:
474 Stack = Stack->Previous;
475 free(Stack->Next);
476 Stack->Next = NULL;
477 Temp = List;
478 ListFirst = List = List->Next;
479 free(Temp);
480 break;
481 case 4:
482 PostFix = PostFix->Next = List;
483 ListFirst = List = List->Next;
484 break;
485 case 5:
486 strcpy(Buffer, "Error in expression");
487 goto End;
488 case 6:
489 PostFix = PostFix->Next = Stack;
490 Stack = Stack->Previous;
491 Stack->Next = NULL;
492 Temp = List;
493 ListFirst = List = List->Next;
494 free(Temp);
495 break;
496 default:
497 strcpy(Buffer, "Internal error");
498 goto End;
499 }
500 }
501
502 /* Now we've got everything in Postfix notation... calculate it now */
503
504 PostFix = PostFixFirst->Next;
505 while (PostFix) {
506 switch (PostFix->Type) {
507 case mNumber:
508 if (!(TheValues->Next = malloc(sizeof(struct Values)))) goto MemError;
509 TheValues->Next->Previous = TheValues;
510 TheValues = TheValues->Next;
511 TheValues->Next = NULL;
512 TheValues->Value = PostFix->Value;
513 break;
514 case mPlus:
515 TheValues->Previous->Value += TheValues->Value;
516 TheValues = TheValues->Previous;
517 free(TheValues->Next);
518 TheValues->Next = NULL;
519 break;
520 case mMinus:
521 TheValues->Previous->Value -= TheValues->Value;
522 TheValues = TheValues->Previous;
523 free(TheValues->Next);
524 TheValues->Next = NULL;
525 break;
526 case mMult:
527 TheValues->Previous->Value *= TheValues->Value;
528 TheValues = TheValues->Previous;
529 free(TheValues->Next);
530 TheValues->Next = NULL;
531 break;
532 case mDiv:
533 if (TheValues->Value == 0) {
534 strcpy(Buffer, "Division by zero error!");
535 goto End;
536 }
537 TheValues->Previous->Value /= TheValues->Value;
538 TheValues = TheValues->Previous;
539 free(TheValues->Next);
540 TheValues->Next = NULL;
541 break;
542 case mPower:
543 TheValues->Previous->Value = pow(TheValues->Previous->Value, TheValues->Value);
544 TheValues = TheValues->Previous;
545 free(TheValues->Next);
546 TheValues->Next = NULL;
547 break;
548 case mEnd:
549 Value = TheValues->Value;
550 break;
551 case mOp:
552 switch (PostFix->OpType) {
553 case otExp:
554 TheValues->Value = exp(TheValues->Value);
555 break;
556 case otLog:
557 if (TheValues->Value <= 0) {
558 strcpy(Buffer, "Log of non-positive value error");
559 goto End;
560 }
561 TheValues->Value = log(TheValues->Value);
562 break;
563 case otSin:
564 TheValues->Value = sin(TheValues->Value);
565 break;
566 case otASin:
567 if (TheValues->Value < -1 || TheValues->Value > 1) {
568 strcpy(Buffer, "Domain error");
569 goto End;
570 }
571 TheValues->Value = asin(TheValues->Value);
572 break;
573 case otSinH:
574 TheValues->Value = sinh(TheValues->Value);
575 case otCos:
576 TheValues->Value = cos(TheValues->Value);
577 break;
578 case otACos:
579 if (TheValues->Value < -1 || TheValues->Value > 1) {
580 strcpy(Buffer, "Domain error");
581 goto End;
582 }
583 TheValues->Value = acos(TheValues->Value);
584 break;
585 case otCosH:
586 TheValues->Value = cosh(TheValues->Value);
587 break;
588 case otTan:
589 TheValues->Value = tan(TheValues->Value);
590 break;
591 case otATan:
592 TheValues->Value = atan(TheValues->Value);
593 break;
594 case otTanH:
595 TheValues->Value = tanh(TheValues->Value);
596 break;
597 case otSqrt:
598 if (TheValues->Value < 0) {
599 strcpy(Buffer, "Sqrt from number < 0");
600 goto End;
601 }
602 TheValues->Value = sqrt(TheValues->Value);
603 break;
604 case otAbs:
605 TheValues->Value = fabs(TheValues->Value);
606 break;
607 case otCeil:
608 TheValues->Value = ceil(TheValues->Value);
609 break;
610 case otFloor:
611 TheValues->Value = floor(TheValues->Value);
612 break;
613 }
614 break;
615 /* The following three do not occur. They are here to prevent compiler warnings */
616 case mLt:
617 case mRt:
618 case mOpEnd:
619 break;
620 }
621 PostFix = PostFix->Next;
622 }
623
624 if (fabs(Value) < 1000000 && (fabs(Value) > 0.001 || Value == 0.0))
625 {
626 if (fabs(Value - floor(Value + 0.5)) < 0.00001) {
627 sprintf(Buffer, "%.0f", Value);
628 }
629 else {
630 sprintf(Buffer, "%f", Value);
631 }
632 }
633 else {
634 sprintf(Buffer, "%E", Value);
635 }
636 End:
637 /* Free up memory here */
638
639 List = ListFirst;
640 while (List) {
641 Temp = List;
642 List = List->Next;
643 free(Temp);
644 }
645
646 Stack = StackFirst;
647 while (Stack) {
648 Temp = Stack;
649 Stack = Stack->Next;
650 free(Temp);
651 }
652
653 PostFix = PostFixFirst;
654 while (PostFix) {
655 Temp = PostFix;
656 PostFix = PostFix->Next;
657 free(Temp);
658 }
659
660 TheValues = TheValuesFirst;
661 while (TheValues) {
662 Temp = TheValues;
663 TheValues = TheValues->Next;
664 free(Temp);
665 }
666
667 return;
668
669 MemError:
670 strcpy(Buffer, "Couldn't allocate enough memory");
671 goto End;
672 }