]>
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
;
128 if (!(List
= ListFirst
= malloc(sizeof(struct MathToken
)))) goto MemError
;
129 if (!(Stack
= StackFirst
= malloc(sizeof(struct MathToken
)))) goto MemError
;
130 if (!(PostFix
= PostFixFirst
= malloc(sizeof(struct MathToken
)))) goto MemError
;
131 if (!(TheValues
= TheValuesFirst
= malloc(sizeof(struct Values
)))) goto MemError
;
135 PostFix
->Next
= NULL
;
136 TheValues
->Next
= NULL
;
138 StackFirst
->Type
= mEnd
;
140 /* First tokenize the buffer */
143 if (isdigit(*Math
) || *Math
== '.') {
144 if (!ValueExpected
) {
145 strcpy(Buffer
, "Unexpected value");
151 while (isdigit(*Math
) || *Math
== '.') {
154 strcpy(Buffer
, "Error in constant");
161 Value
= Value
* 10 + *Math
- '0';
163 Floating
= Floating
* 10;
164 Value
= Value
+ (*Math
- '0') / Floating
;
168 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
170 List
->Type
= mNumber
;
173 List
->Value
= -Value
;
178 else switch (*Math
) {
186 if (*Math
== '-' && ValueExpected
) {
191 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto End
;
194 case '+': List
->Type
= mPlus
; break;
195 case '-': List
->Type
= mMinus
; break;
196 case '*': List
->Type
= mMult
; break;
197 case '/': List
->Type
= mDiv
; break;
198 case '^': List
->Type
= mPower
; break;
199 case '(': List
->Type
= mLt
; break;
200 case ')': List
->Type
= mRt
; break;
201 case ']': List
->Type
= mOpEnd
; break;
203 if (*Math
!= '(' && ValueExpected
) {
204 strcpy(Buffer
, "Value expected");
207 if (*Math
!= ')' && *Math
!= ']')
212 if (isalpha(*Math
)) {
214 while (isalpha(*Math
))
215 Identifier
[Index
++] = *Math
++;
216 Identifier
[Index
] = '\0';
218 if (!ValueExpected
) {
219 strcpy(Buffer
, "Unexpected value");
222 if (!strcasecmp(Identifier
, "e")) {
223 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
225 List
->Type
= mNumber
;
226 List
->Value
= exp(1);
229 else if (!strcasecmp(Identifier
, "pi")) {
230 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
232 List
->Type
= mNumber
;
233 List
->Value
= 4 * atan(1);
236 else if (!strcasecmp(Identifier
, "rand")) {
237 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
239 List
->Type
= mNumber
;
240 List
->Value
= (double)rand() / (double)RAND_MAX
;
243 else if (!strcasecmp(Identifier
, "exp")) {
244 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
247 List
->OpType
= otExp
;
250 else if (!strcasecmp(Identifier
, "log")) {
251 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
254 List
->OpType
= otLog
;
257 else if (!strcasecmp(Identifier
, "sin")) {
258 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
261 List
->OpType
= otSin
;
264 else if (!strcasecmp(Identifier
, "asin")) {
265 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
268 List
->OpType
= otASin
;
271 else if (!strcasecmp(Identifier
, "sinh")) {
272 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
275 List
->OpType
= otSinH
;
278 else if (!strcasecmp(Identifier
, "cos")) {
279 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
282 List
->OpType
= otCos
;
285 else if (!strcasecmp(Identifier
, "acos")) {
286 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
289 List
->OpType
= otACos
;
292 else if (!strcasecmp(Identifier
, "cosh")) {
293 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
296 List
->OpType
= otCosH
;
299 else if (!strcasecmp(Identifier
, "tan")) {
300 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
303 List
->OpType
= otTan
;
306 else if (!strcasecmp(Identifier
, "atan")) {
307 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
310 List
->OpType
= otATan
;
313 else if (!strcasecmp(Identifier
, "tanh")) {
314 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
317 List
->OpType
= otTanH
;
320 else if (!strcasecmp(Identifier
, "sqrt")) {
321 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
324 List
->OpType
= otSqrt
;
327 else if (!strcasecmp(Identifier
, "abs")) {
328 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
331 List
->OpType
= otAbs
;
334 else if (!strcasecmp(Identifier
, "ceil")) {
335 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
338 List
->OpType
= otCeil
;
341 else if (!strcasecmp(Identifier
, "floor")) {
342 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
345 List
->OpType
= otFloor
;
349 strcpy(Buffer
, "Unexpected Identifier");
353 while (*Math
== ' ' || *Math
== '\t')
356 strcpy(Buffer
, "'[' expected");
363 strcpy(Buffer
, "Unknown character in expression");
369 strcpy(Buffer
, "Value expected");
372 if (!(List
= List
->Next
= malloc(sizeof(struct MathToken
)))) goto MemError
;
376 /* We've got them tokenized now... now convert it
377 from infix notation to postfix notation */
379 List
= ListFirst
->Next
;
381 if (List
->Type
== mNumber
) {
382 PostFix
= PostFix
->Next
= List
;
383 ListFirst
= List
= List
->Next
;
384 PostFix
->Next
= NULL
;
386 else switch (TranslateTable
[Stack
->Type
][List
->Type
]) {
388 List
->Previous
= Stack
;
389 Stack
= Stack
->Next
= List
;
390 ListFirst
= List
= List
->Next
;
394 PostFix
= PostFix
->Next
= Stack
;
395 Stack
= Stack
->Previous
;
399 Stack
= Stack
->Previous
;
403 ListFirst
= List
= List
->Next
;
407 PostFix
= PostFix
->Next
= List
;
408 ListFirst
= List
= List
->Next
;
411 strcpy(Buffer
, "Error in expression");
414 PostFix
= PostFix
->Next
= Stack
;
415 Stack
= Stack
->Previous
;
418 ListFirst
= List
= List
->Next
;
422 strcpy(Buffer
, "Internal error");
427 /* Now we've got everything in Postfix notation... calculate it now */
429 PostFix
= PostFixFirst
->Next
;
431 switch (PostFix
->Type
) {
433 if (!(TheValues
->Next
= malloc(sizeof(struct Values
)))) goto MemError
;
434 TheValues
->Next
->Previous
= TheValues
;
435 TheValues
= TheValues
->Next
;
436 TheValues
->Next
= NULL
;
437 TheValues
->Value
= PostFix
->Value
;
440 TheValues
->Previous
->Value
+= TheValues
->Value
;
441 TheValues
= TheValues
->Previous
;
442 free(TheValues
->Next
);
443 TheValues
->Next
= NULL
;
446 TheValues
->Previous
->Value
-= TheValues
->Value
;
447 TheValues
= TheValues
->Previous
;
448 free(TheValues
->Next
);
449 TheValues
->Next
= NULL
;
452 TheValues
->Previous
->Value
*= TheValues
->Value
;
453 TheValues
= TheValues
->Previous
;
454 free(TheValues
->Next
);
455 TheValues
->Next
= NULL
;
458 if (TheValues
->Value
== 0) {
459 strcpy(Buffer
, "Division by zero error!");
462 TheValues
->Previous
->Value
/= TheValues
->Value
;
463 TheValues
= TheValues
->Previous
;
464 free(TheValues
->Next
);
465 TheValues
->Next
= NULL
;
468 TheValues
->Previous
->Value
= pow(TheValues
->Previous
->Value
, TheValues
->Value
);
469 TheValues
= TheValues
->Previous
;
470 free(TheValues
->Next
);
471 TheValues
->Next
= NULL
;
474 Value
= TheValues
->Value
;
477 switch (PostFix
->OpType
) {
479 TheValues
->Value
= exp(TheValues
->Value
);
482 if (TheValues
->Value
<= 0) {
483 strcpy(Buffer
, "Log of non-positive value error");
486 TheValues
->Value
= log(TheValues
->Value
);
489 TheValues
->Value
= sin(TheValues
->Value
);
492 if (TheValues
->Value
< -1 || TheValues
->Value
> 1) {
493 strcpy(Buffer
, "Domain error");
496 TheValues
->Value
= asin(TheValues
->Value
);
499 TheValues
->Value
= sinh(TheValues
->Value
);
501 TheValues
->Value
= cos(TheValues
->Value
);
504 if (TheValues
->Value
< -1 || TheValues
->Value
> 1) {
505 strcpy(Buffer
, "Domain error");
508 TheValues
->Value
= acos(TheValues
->Value
);
511 TheValues
->Value
= cosh(TheValues
->Value
);
514 TheValues
->Value
= tan(TheValues
->Value
);
517 TheValues
->Value
= atan(TheValues
->Value
);
520 TheValues
->Value
= tanh(TheValues
->Value
);
523 if (TheValues
->Value
< 0) {
524 strcpy(Buffer
, "Sqrt from number < 0");
527 TheValues
->Value
= sqrt(TheValues
->Value
);
530 TheValues
->Value
= fabs(TheValues
->Value
);
533 TheValues
->Value
= ceil(TheValues
->Value
);
536 TheValues
->Value
= floor(TheValues
->Value
);
540 /* The following three do not occur. They are here to prevent compiler warnings */
546 PostFix
= PostFix
->Next
;
549 if (fabs(Value
) < 1000000 && (fabs(Value
) > 0.001 || Value
== 0.0))
551 if (fabs(Value
- floor(Value
+ 0.5)) < 0.00001) {
552 sprintf(Buffer
, "%.0f", Value
);
555 sprintf(Buffer
, "%f", Value
);
559 sprintf(Buffer
, "%E", Value
);
562 /* Free up memory here */
578 PostFix
= PostFixFirst
;
581 PostFix
= PostFix
->Next
;
585 TheValues
= TheValuesFirst
;
588 TheValues
= TheValues
->Next
;
595 strcpy(Buffer
, "Couldn't allocate enough memory");