]> git.zerfleddert.de Git - micropolis/blame - src/tclx/src/tclxfmat.c
glibc 2.27
[micropolis] / src / tclx / src / tclxfmat.c
CommitLineData
6a5fa4e0
MG
1/*
2 * tclXfmath.c --
3 *
4 * Contains the TCL trig and floating point math functions.
5 *-----------------------------------------------------------------------------
6 * Copyright 1992 Karl Lehenbauer and Mark Diekhans.
7 *
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation for any purpose and without fee is hereby granted, provided
10 * that the above copyright notice appear in all copies. Karl Lehenbauer and
11 * Mark Diekhans make no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
13 * implied warranty.
14 *-----------------------------------------------------------------------------
15 * $Id: tclXfmath.c,v 2.5 1992/11/09 07:58:13 markd Exp $
16 *-----------------------------------------------------------------------------
17 */
18
19#include "tclxint.h"
20#include <math.h>
21
22/*
23 * Flag used to indicate if a floating point math routine is currently being
24 * executed. Used to determine if a matherr belongs to Tcl.
25 */
26static int G_inTclFPMath = FALSE;
27
28/*
29 * Flag indicating if a floating point math error occured during the execution
30 * of a library routine called by a Tcl command. Will not be set by the trap
31 * handler if the error did not occur while the `G_inTclFPMath' flag was
32 * set. If the error did occur the error type and the name of the function
33 * that got the error are save here.
34 */
35static int G_gotTclFPMathErr = FALSE;
36static int G_errorType;
37
38/*
39 * Prototypes of internal functions.
40 */
41#ifdef TCL_IEEE_FP_MATH
42static int
43ReturnIEEEMathError _ANSI_ARGS_((Tcl_Interp *interp,
44 double dbResult));
45#else
46static int
47ReturnFPMathError _ANSI_ARGS_((Tcl_Interp *interp));
48#endif
49
50static int
51Tcl_UnaryFloatFunction _ANSI_ARGS_((Tcl_Interp *interp,
52 int argc,
53 char **argv,
54 double (*function)()));
55
56
57#ifdef TCL_IEEE_FP_MATH
58\f
59/*
60 *-----------------------------------------------------------------------------
61 *
62 * ReturnIEEEMathError --
63 * Handle return of floating point errors on machines that use IEEE 745-1985
64 * error reporting instead of Unix matherr. Some machines support both and
65 * on these, either option may be used.
66 * Various tests are used to determine if a number is one of the special
67 * values. Not-a-number is tested by comparing the number against itself
68 * (x != x if x is NaN). Infinity is tested for by comparing against MAXDOUBLE.
69 *
70 * Parameters:
71 * o interp (I) - Error is returned in result.
72 * o dbResult (I) - Result of a function call that returned a special value.
73 * Returns:
74 * Always returns the value TCL_ERROR, so if can be called as the
75 * argument to `return'.
76 *-----------------------------------------------------------------------------
77 */
78static int
79ReturnIEEEMathError (interp, dbResult)
80 Tcl_Interp *interp;
81 double dbResult;
82{
83 char *errorMsg;
84
85 if (dbResult != dbResult)
86 errorMsg = "domain";
87 else if (dbResult > MAXDOUBLE)
88 errorMsg = "overflow";
89 else if (dbResult < -MAXDOUBLE)
90 errorMsg = "underflow";
91
92 Tcl_AppendResult (interp, "floating point ", errorMsg, " error",
93 (char *) NULL);
94 return TCL_ERROR;
95}
96#else
97\f
98/*
99 *-----------------------------------------------------------------------------
100 *
101 * ReturnFPMathError --
102 * Routine to set an interpreter result to contain a floating point
103 * math error message. Will clear the `G_gotTclFPMathErr' flag.
104 * This routine always returns the value TCL_ERROR, so if can be called
105 * as the argument to `return'.
106 *
107 * Parameters:
108 * o interp (I) - Error is returned in result.
109 * Globals:
110 * o G_gotTclFPMathErr (O) - Flag indicating an error occured, will be
111 * cleared.
112 * o G_errorType (I) - Type of error that occured.
113 * Returns:
114 * Always returns the value TCL_ERROR, so if can be called as the
115 * argument to `return'.
116 *-----------------------------------------------------------------------------
117 */
118static int
119ReturnFPMathError (interp)
120 Tcl_Interp *interp;
121{
6a5fa4e0 122
59dd70c3 123 Tcl_AppendResult (interp, "floating point error",
6a5fa4e0
MG
124 (char *) NULL);
125 G_gotTclFPMathErr = FALSE; /* Clear the flag. */
126 return TCL_ERROR;
127}
128#endif /* NO_MATH_ERR */
129\f
130/*
131 *-----------------------------------------------------------------------------
132 *
133 * Tcl_MathError --
134 * Tcl math error handler, should be called by an application `matherr'
135 * routine to determine if an error was caused by Tcl code or by other
136 * code in the application. If the error occured in Tcl code, flags will
137 * be set so that a standard Tcl interpreter error can be returned.
138 *
139 * Paramenter:
140 * o functionName (I) - The name of the function that got the error. From
141 * the exception structure supplied to matherr.
142 * o errorType (I) - The type of error that occured. From the exception
143 * structure supplied to matherr.
144 * Results:
145 * Returns TRUE if the error was in Tcl code, in which case the
146 * matherr routine calling this function should return non-zero so no
147 * error message will be generated. FALSE if the error was not in Tcl
148 * code, in which case the matherr routine can handle the error in any
149 * manner it choses.
150 *
151 *-----------------------------------------------------------------------------
152 */
153int
154Tcl_MathError (functionName, errorType)
155 char *functionName;
156 int errorType;
157{
158
159 if (G_inTclFPMath) {
160 G_gotTclFPMathErr = TRUE;
161 G_errorType = errorType;
162 return TRUE;
163 } else
164 return FALSE;
165
166}
167\f
168/*
169 *-----------------------------------------------------------------------------
170 *
171 * Tcl_UnaryFloatFunction --
172 * Helper routine that implements Tcl unary floating point
173 * functions by validating parameters, converting the
174 * argument, applying the function (the address of which
175 * is passed as an argument), and converting the result to
176 * a string and storing it in the result buffer
177 *
178 * Results:
179 * Returns TCL_OK if number is present, conversion succeeded,
180 * the function was performed, etc.
181 * Return TCL_ERROR for any error; an appropriate error message
182 * is placed in the result string in this case.
183 *
184 *-----------------------------------------------------------------------------
185 */
186static int
187Tcl_UnaryFloatFunction(interp, argc, argv, function)
188 Tcl_Interp *interp;
189 int argc;
190 char **argv;
191 double (*function)();
192{
193 double dbVal, dbResult;
194
195 if (argc != 2) {
196 Tcl_AppendResult (interp, tclXWrongArgs, argv [0], " expr",
197 (char *) NULL);
198 return TCL_ERROR;
199 }
200
201 if (Tcl_ExprDouble (interp, argv [1], &dbVal) != TCL_OK)
202 return TCL_ERROR;
203
204 G_inTclFPMath = TRUE;
205 dbResult = (*function)(dbVal);
206 G_inTclFPMath = FALSE;
207
208#ifdef TCL_IEEE_FP_MATH
209 if ((dbResult != dbResult) ||
210 (dbResult < -MAXDOUBLE) ||
211 (dbResult > MAXDOUBLE))
212 return ReturnIEEEMathError (interp, dbResult);
213#else
214 if (G_gotTclFPMathErr)
215 return ReturnFPMathError (interp);
216#endif
217
218 Tcl_ReturnDouble (interp, dbResult);
219 return TCL_OK;
220}
221\f
222/*
223 *-----------------------------------------------------------------------------
224 *
225 * Tcl_AcosCmd --
226 * Implements the TCL arccosine command:
227 * acos num
228 *
229 * Results:
230 * Returns TCL_OK if number is present and conversion succeeds.
231 *
232 *-----------------------------------------------------------------------------
233 */
234int
235Tcl_AcosCmd(clientData, interp, argc, argv)
236 ClientData clientData;
237 Tcl_Interp *interp;
238 int argc;
239 char **argv;
240{
241 return Tcl_UnaryFloatFunction(interp, argc, argv, acos);
242}
243\f
244/*
245 *-----------------------------------------------------------------------------
246 *
247 * Tcl_AsinCmd --
248 * Implements the TCL arcsin command:
249 * asin num
250 *
251 * Results:
252 * Returns TCL_OK if number is present and conversion succeeds.
253 *
254 *-----------------------------------------------------------------------------
255 */
256int
257Tcl_AsinCmd(clientData, interp, argc, argv)
258 ClientData clientData;
259 Tcl_Interp *interp;
260 int argc;
261 char **argv;
262{
263 return Tcl_UnaryFloatFunction(interp, argc, argv, asin);
264}
265\f
266/*
267 *-----------------------------------------------------------------------------
268 *
269 * Tcl_AtanCmd --
270 * Implements the TCL arctangent command:
271 * atan num
272 *
273 * Results:
274 * Returns TCL_OK if number is present and conversion succeeds.
275 *
276 *-----------------------------------------------------------------------------
277 */
278int
279Tcl_AtanCmd(clientData, interp, argc, argv)
280 ClientData clientData;
281 Tcl_Interp *interp;
282 int argc;
283 char **argv;
284{
285 return Tcl_UnaryFloatFunction(interp, argc, argv, atan);
286}
287\f
288/*
289 *-----------------------------------------------------------------------------
290 *
291 * Tcl_CosCmd --
292 * Implements the TCL cosine command:
293 * cos num
294 *
295 * Results:
296 * Returns TCL_OK if number is present and conversion succeeds.
297 *
298 *-----------------------------------------------------------------------------
299 */
300int
301Tcl_CosCmd(clientData, interp, argc, argv)
302 ClientData clientData;
303 Tcl_Interp *interp;
304 int argc;
305 char **argv;
306{
307 return Tcl_UnaryFloatFunction(interp, argc, argv, cos);
308}
309\f
310/*
311 *-----------------------------------------------------------------------------
312 *
313 * Tcl_SinCmd --
314 * Implements the TCL sin command:
315 * sin num
316 *
317 * Results:
318 * Returns TCL_OK if number is present and conversion succeeds.
319 *
320 *-----------------------------------------------------------------------------
321 */
322int
323Tcl_SinCmd(clientData, interp, argc, argv)
324 ClientData clientData;
325 Tcl_Interp *interp;
326 int argc;
327 char **argv;
328{
329 return Tcl_UnaryFloatFunction(interp, argc, argv, sin);
330}
331\f
332/*
333 *-----------------------------------------------------------------------------
334 *
335 * Tcl_TanCmd --
336 * Implements the TCL tangent command:
337 * tan num
338 *
339 * Results:
340 * Returns TCL_OK if number is present and conversion succeeds.
341 *
342 *-----------------------------------------------------------------------------
343 */
344int
345Tcl_TanCmd(clientData, interp, argc, argv)
346 ClientData clientData;
347 Tcl_Interp *interp;
348 int argc;
349 char **argv;
350{
351 return Tcl_UnaryFloatFunction(interp, argc, argv, tan);
352}
353\f
354/*
355 *-----------------------------------------------------------------------------
356 *
357 * Tcl_CoshCmd --
358 * Implements the TCL hyperbolic cosine command:
359 * cosh num
360 *
361 * Results:
362 * Returns TCL_OK if number is present and conversion succeeds.
363 *
364 *-----------------------------------------------------------------------------
365 */
366int
367Tcl_CoshCmd(clientData, interp, argc, argv)
368 ClientData clientData;
369 Tcl_Interp *interp;
370 int argc;
371 char **argv;
372{
373 return Tcl_UnaryFloatFunction(interp, argc, argv, cosh);
374}
375\f
376/*
377 *-----------------------------------------------------------------------------
378 *
379 * Tcl_SinhCmd --
380 * Implements the TCL hyperbolic sin command:
381 * sinh num
382 *
383 * Results:
384 * Returns TCL_OK if number is present and conversion succeeds.
385 *
386 *-----------------------------------------------------------------------------
387 */
388int
389Tcl_SinhCmd(clientData, interp, argc, argv)
390 ClientData clientData;
391 Tcl_Interp *interp;
392 int argc;
393 char **argv;
394{
395 return Tcl_UnaryFloatFunction(interp, argc, argv, sinh);
396}
397\f
398/*
399 *-----------------------------------------------------------------------------
400 *
401 * Tcl_TanhCmd --
402 * Implements the TCL hyperbolic tangent command:
403 * tanh num
404 *
405 * Results:
406 * Returns TCL_OK if number is present and conversion succeeds.
407 *
408 *-----------------------------------------------------------------------------
409 */
410int
411Tcl_TanhCmd(clientData, interp, argc, argv)
412 ClientData clientData;
413 Tcl_Interp *interp;
414 int argc;
415 char **argv;
416{
417 return Tcl_UnaryFloatFunction(interp, argc, argv, tanh);
418}
419\f
420/*
421 *-----------------------------------------------------------------------------
422 *
423 * Tcl_ExpCmd --
424 * Implements the TCL exponent command:
425 * exp num
426 *
427 * Results:
428 * Returns TCL_OK if number is present and conversion succeeds.
429 *
430 *-----------------------------------------------------------------------------
431 */
432int
433Tcl_ExpCmd(clientData, interp, argc, argv)
434 ClientData clientData;
435 Tcl_Interp *interp;
436 int argc;
437 char **argv;
438{
439 return Tcl_UnaryFloatFunction(interp, argc, argv, exp);
440}
441\f
442/*
443 *-----------------------------------------------------------------------------
444 *
445 * Tcl_LogCmd --
446 * Implements the TCL logarithm command:
447 * log num
448 *
449 * Results:
450 * Returns TCL_OK if number is present and conversion succeeds.
451 *
452 *-----------------------------------------------------------------------------
453 */
454int
455Tcl_LogCmd(clientData, interp, argc, argv)
456 ClientData clientData;
457 Tcl_Interp *interp;
458 int argc;
459 char **argv;
460{
461 return Tcl_UnaryFloatFunction(interp, argc, argv, log);
462}
463\f
464/*
465 *-----------------------------------------------------------------------------
466 *
467 * Tcl_Log10Cmd --
468 * Implements the TCL base-10 logarithm command:
469 * log10 num
470 *
471 * Results:
472 * Returns TCL_OK if number is present and conversion succeeds.
473 *
474 *-----------------------------------------------------------------------------
475 */
476int
477Tcl_Log10Cmd(clientData, interp, argc, argv)
478 ClientData clientData;
479 Tcl_Interp *interp;
480 int argc;
481 char **argv;
482{
483 return Tcl_UnaryFloatFunction(interp, argc, argv, log10);
484}
485\f
486/*
487 *-----------------------------------------------------------------------------
488 *
489 * Tcl_SqrtCmd --
490 * Implements the TCL square root command:
491 * sqrt num
492 *
493 * Results:
494 * Returns TCL_OK if number is present and conversion succeeds.
495 *
496 *-----------------------------------------------------------------------------
497 */
498int
499Tcl_SqrtCmd(clientData, interp, argc, argv)
500 ClientData clientData;
501 Tcl_Interp *interp;
502 int argc;
503 char **argv;
504{
505 return Tcl_UnaryFloatFunction(interp, argc, argv, sqrt);
506}
507\f
508/*
509 *-----------------------------------------------------------------------------
510 *
511 * Tcl_FabsCmd --
512 * Implements the TCL floating point absolute value command:
513 * fabs num
514 *
515 * Results:
516 * Returns TCL_OK if number is present and conversion succeeds.
517 *
518 *-----------------------------------------------------------------------------
519 */
520int
521Tcl_FabsCmd(clientData, interp, argc, argv)
522 ClientData clientData;
523 Tcl_Interp *interp;
524 int argc;
525 char **argv;
526{
527 return Tcl_UnaryFloatFunction(interp, argc, argv, fabs);
528}
529\f
530/*
531 *-----------------------------------------------------------------------------
532 *
533 * Tcl_FloorCmd --
534 * Implements the TCL floor command:
535 * floor num
536 *
537 * Results:
538 * Returns TCL_OK if number is present and conversion succeeds.
539 *
540 *-----------------------------------------------------------------------------
541 */
542int
543Tcl_FloorCmd(clientData, interp, argc, argv)
544 ClientData clientData;
545 Tcl_Interp *interp;
546 int argc;
547 char **argv;
548{
549 return Tcl_UnaryFloatFunction(interp, argc, argv, floor);
550}
551\f
552/*
553 *-----------------------------------------------------------------------------
554 *
555 * Tcl_CeilCmd --
556 * Implements the TCL ceil command:
557 * ceil num
558 *
559 * Results:
560 * Returns TCL_OK if number is present and conversion succeeds.
561 *
562 *-----------------------------------------------------------------------------
563 */
564int
565Tcl_CeilCmd(clientData, interp, argc, argv)
566 ClientData clientData;
567 Tcl_Interp *interp;
568 int argc;
569 char **argv;
570{
571 return Tcl_UnaryFloatFunction(interp, argc, argv, ceil);
572}
573\f
574/*
575 *-----------------------------------------------------------------------------
576 *
577 * Tcl_FmodCmd --
578 * Implements the TCL floating modulo command:
579 * fmod num1 num2
580 *
581 * Results:
582 * Returns TCL_OK if number is present and conversion succeeds.
583 *
584 *-----------------------------------------------------------------------------
585 */
586int
587Tcl_FmodCmd(clientData, interp, argc, argv)
588 ClientData clientData;
589 Tcl_Interp *interp;
590 int argc;
591 char **argv;
592{
593 double dbVal, dbDivisor, dbResult;
594
595 if (argc != 3) {
596 Tcl_AppendResult (interp, tclXWrongArgs, argv [0], " expr divisor",
597 (char *) NULL);
598 return TCL_ERROR;
599 }
600
601 if (Tcl_ExprDouble (interp, argv [1], &dbVal) != TCL_OK)
602 return TCL_ERROR;
603
604 if (Tcl_ExprDouble (interp, argv [2], &dbDivisor) != TCL_OK)
605 return TCL_ERROR;
606
607 G_inTclFPMath = TRUE;
608 dbResult = fmod (dbVal, dbDivisor);
609 G_inTclFPMath = FALSE;
610
611#ifdef TCL_IEEE_FP_MATH
612 if ((dbResult != dbResult) ||
613 (dbResult < -MAXDOUBLE) ||
614 (dbResult > MAXDOUBLE))
615 return ReturnIEEEMathError (interp, dbResult);
616#else
617 if (G_gotTclFPMathErr)
618 return ReturnFPMathError (interp);
619#endif
620
621 Tcl_ReturnDouble (interp, dbResult);
622 return TCL_OK;
623}
624\f
625/*
626 *-----------------------------------------------------------------------------
627 *
628 * Tcl_PowCmd --
629 * Implements the TCL power (exponentiation) command:
630 * pow num1 num2
631 *
632 * Results:
633 * Returns TCL_OK if number is present and conversion succeeds.
634 *
635 *-----------------------------------------------------------------------------
636 */
637int
638Tcl_PowCmd(clientData, interp, argc, argv)
639 ClientData clientData;
640 Tcl_Interp *interp;
641 int argc;
642 char **argv;
643{
644 double dbVal, dbExp, dbResult;
645
646 if (argc != 3) {
647 Tcl_AppendResult (interp, tclXWrongArgs, argv [0], " expr exp",
648 (char *) NULL);
649 return TCL_ERROR;
650 }
651
652 if (Tcl_ExprDouble (interp, argv [1], &dbVal) != TCL_OK)
653 return TCL_ERROR;
654
655 if (Tcl_ExprDouble (interp, argv [2], &dbExp) != TCL_OK)
656 return TCL_ERROR;
657
658 G_inTclFPMath = TRUE;
659 dbResult = pow (dbVal,dbExp);
660 G_inTclFPMath = FALSE;
661
662#ifdef TCL_IEEE_FP_MATH
663 if ((dbResult != dbResult) ||
664 (dbResult < -MAXDOUBLE) ||
665 (dbResult > MAXDOUBLE))
666 return ReturnIEEEMathError (interp, dbResult);
667#else
668 if (G_gotTclFPMathErr)
669 return ReturnFPMathError (interp);
670#endif
671
672 Tcl_ReturnDouble (interp, dbResult);
673 return TCL_OK;
674}
Impressum, Datenschutz