]>
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.
41 #define strcasecmp stricmp
76 /* This table is needed for the translation from infix to postfix. */
77 static const int TranslateTable
[][10] = {
78 /*List: _ + - * / ^ ( ) [ ] */
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}
92 typedef struct MathToken
{
95 enum MathOpType OpType
;
96 struct MathToken
*Next
;
97 struct MathToken
*Previous
; /* Previous is used in the stack */
100 typedef struct Values
{
103 struct Values
*Previous
;
106 void do_math(char *Buffer
, char *Math
)
110 double Floating
; /* = 10^number of digits after the dot */
111 int ValueExpected
= 1;
112 char Identifier
[512];
114 MathList ListFirst
= NULL
;
115 MathList StackFirst
= NULL
;
116 MathList PostFixFirst
= NULL
;
117 ValueList TheValuesFirst
= NULL
;
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
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
135 char newMath
[MAXLEN
];
137 char lastNumber
= false;
138 char lastBracket
= false;
142 while(*Math
&& ptr
< newMath
+MAXLEN
-1)
152 if(lastBracket
== true)
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 */
174 if (lastNumber
== true)
186 if(lastNumber
== true)
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
;
210 PostFix
->Next
= NULL
;
211 TheValues
->Next
= NULL
;
213 StackFirst
->Type
= mEnd
;
215 /* First tokenize the buffer */
218 if (isdigit(*Math
) || *Math
== '.') {
219 if (!ValueExpected
) {
220 strcpy(Buffer
, "Unexpected value");
226 while (isdigit(*Math
) || *Math
== '.') {
229 strcpy(Buffer
, "Error in constant");
236 Value
= Value
* 10 + *Math
- '0';
238 Floating
= Floating
* 10;
239 Value
= Value
+ (*Math
- '0') / Floating
;
243 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
245 List
->Type
= mNumber
;
248 List
->Value
= -Value
;
253 else switch (*Math
) {
261 if (*Math
== '-' && ValueExpected
) {
266 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto End
;
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;
278 if (*Math
!= '(' && ValueExpected
) {
279 strcpy(Buffer
, "Value expected");
282 if (*Math
!= ')' && *Math
!= ']')
287 if (isalpha(*Math
)) {
289 while (isalpha(*Math
))
290 Identifier
[Index
++] = *Math
++;
291 Identifier
[Index
] = '\0';
293 if (!ValueExpected
) {
294 strcpy(Buffer
, "Unexpected value");
297 if (!strcasecmp(Identifier
, "e")) {
298 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
300 List
->Type
= mNumber
;
301 List
->Value
= exp(1);
304 else if (!strcasecmp(Identifier
, "pi")) {
305 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
307 List
->Type
= mNumber
;
308 List
->Value
= 4 * atan(1);
311 else if (!strcasecmp(Identifier
, "rand")) {
312 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
314 List
->Type
= mNumber
;
315 List
->Value
= (double)rand() / (double)RAND_MAX
;
318 else if (!strcasecmp(Identifier
, "exp")) {
319 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
322 List
->OpType
= otExp
;
325 else if (!strcasecmp(Identifier
, "log")) {
326 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
329 List
->OpType
= otLog
;
332 else if (!strcasecmp(Identifier
, "sin")) {
333 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
336 List
->OpType
= otSin
;
339 else if (!strcasecmp(Identifier
, "asin")) {
340 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
343 List
->OpType
= otASin
;
346 else if (!strcasecmp(Identifier
, "sinh")) {
347 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
350 List
->OpType
= otSinH
;
353 else if (!strcasecmp(Identifier
, "cos")) {
354 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
357 List
->OpType
= otCos
;
360 else if (!strcasecmp(Identifier
, "acos")) {
361 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
364 List
->OpType
= otACos
;
367 else if (!strcasecmp(Identifier
, "cosh")) {
368 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
371 List
->OpType
= otCosH
;
374 else if (!strcasecmp(Identifier
, "tan")) {
375 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
378 List
->OpType
= otTan
;
381 else if (!strcasecmp(Identifier
, "atan")) {
382 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
385 List
->OpType
= otATan
;
388 else if (!strcasecmp(Identifier
, "tanh")) {
389 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
392 List
->OpType
= otTanH
;
395 else if (!strcasecmp(Identifier
, "sqrt")) {
396 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
399 List
->OpType
= otSqrt
;
402 else if (!strcasecmp(Identifier
, "abs")) {
403 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
406 List
->OpType
= otAbs
;
409 else if (!strcasecmp(Identifier
, "ceil")) {
410 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
413 List
->OpType
= otCeil
;
416 else if (!strcasecmp(Identifier
, "floor")) {
417 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
420 List
->OpType
= otFloor
;
424 strcpy(Buffer
, "Unexpected Identifier");
428 while (*Math
== ' ' || *Math
== '\t')
431 strcpy(Buffer
, "'[' expected");
438 strcpy(Buffer
, "Unknown character in expression");
444 strcpy(Buffer
, "Value expected");
447 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
451 /* We've got them tokenized now... now convert it
452 from infix notation to postfix notation */
454 List
= ListFirst
->Next
;
456 if (List
->Type
== mNumber
) {
457 PostFix
= PostFix
->Next
= List
;
458 ListFirst
= List
= List
->Next
;
459 PostFix
->Next
= NULL
;
461 else switch (TranslateTable
[Stack
->Type
][List
->Type
]) {
463 List
->Previous
= Stack
;
464 Stack
= Stack
->Next
= List
;
465 ListFirst
= List
= List
->Next
;
469 PostFix
= PostFix
->Next
= Stack
;
470 Stack
= Stack
->Previous
;
474 Stack
= Stack
->Previous
;
478 ListFirst
= List
= List
->Next
;
482 PostFix
= PostFix
->Next
= List
;
483 ListFirst
= List
= List
->Next
;
486 strcpy(Buffer
, "Error in expression");
489 PostFix
= PostFix
->Next
= Stack
;
490 Stack
= Stack
->Previous
;
493 ListFirst
= List
= List
->Next
;
497 strcpy(Buffer
, "Internal error");
502 /* Now we've got everything in Postfix notation... calculate it now */
504 PostFix
= PostFixFirst
->Next
;
506 switch (PostFix
->Type
) {
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
;
515 TheValues
->Previous
->Value
+= TheValues
->Value
;
516 TheValues
= TheValues
->Previous
;
517 free(TheValues
->Next
);
518 TheValues
->Next
= NULL
;
521 TheValues
->Previous
->Value
-= TheValues
->Value
;
522 TheValues
= TheValues
->Previous
;
523 free(TheValues
->Next
);
524 TheValues
->Next
= NULL
;
527 TheValues
->Previous
->Value
*= TheValues
->Value
;
528 TheValues
= TheValues
->Previous
;
529 free(TheValues
->Next
);
530 TheValues
->Next
= NULL
;
533 if (TheValues
->Value
== 0) {
534 strcpy(Buffer
, "Division by zero error!");
537 TheValues
->Previous
->Value
/= TheValues
->Value
;
538 TheValues
= TheValues
->Previous
;
539 free(TheValues
->Next
);
540 TheValues
->Next
= NULL
;
543 TheValues
->Previous
->Value
= pow(TheValues
->Previous
->Value
, TheValues
->Value
);
544 TheValues
= TheValues
->Previous
;
545 free(TheValues
->Next
);
546 TheValues
->Next
= NULL
;
549 Value
= TheValues
->Value
;
552 switch (PostFix
->OpType
) {
554 TheValues
->Value
= exp(TheValues
->Value
);
557 if (TheValues
->Value
<= 0) {
558 strcpy(Buffer
, "Log of non-positive value error");
561 TheValues
->Value
= log(TheValues
->Value
);
564 TheValues
->Value
= sin(TheValues
->Value
);
567 if (TheValues
->Value
< -1 || TheValues
->Value
> 1) {
568 strcpy(Buffer
, "Domain error");
571 TheValues
->Value
= asin(TheValues
->Value
);
574 TheValues
->Value
= sinh(TheValues
->Value
);
576 TheValues
->Value
= cos(TheValues
->Value
);
579 if (TheValues
->Value
< -1 || TheValues
->Value
> 1) {
580 strcpy(Buffer
, "Domain error");
583 TheValues
->Value
= acos(TheValues
->Value
);
586 TheValues
->Value
= cosh(TheValues
->Value
);
589 TheValues
->Value
= tan(TheValues
->Value
);
592 TheValues
->Value
= atan(TheValues
->Value
);
595 TheValues
->Value
= tanh(TheValues
->Value
);
598 if (TheValues
->Value
< 0) {
599 strcpy(Buffer
, "Sqrt from number < 0");
602 TheValues
->Value
= sqrt(TheValues
->Value
);
605 TheValues
->Value
= fabs(TheValues
->Value
);
608 TheValues
->Value
= ceil(TheValues
->Value
);
611 TheValues
->Value
= floor(TheValues
->Value
);
615 /* The following three do not occur. They are here to prevent compiler warnings */
621 PostFix
= PostFix
->Next
;
624 if (fabs(Value
) < 1000000 && (fabs(Value
) > 0.001 || Value
== 0.0))
626 if (fabs(Value
- floor(Value
+ 0.5)) < 0.00001) {
627 sprintf(Buffer
, "%.0f", Value
);
630 sprintf(Buffer
, "%f", Value
);
634 sprintf(Buffer
, "%E", Value
);
637 /* Free up memory here */
653 PostFix
= PostFixFirst
;
656 PostFix
= PostFix
->Next
;
660 TheValues
= TheValuesFirst
;
663 TheValues
= TheValues
->Next
;
670 strcpy(Buffer
, "Couldn't allocate enough memory");