2 * mathfunc.c - basic mathematical functions for use in math evaluations
4 * This file is part of zsh, the Z shell.
6 * Copyright (c) 1999 Peter Stephenson
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
15 * In no event shall Peter Stephenson or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Peter Stephenson and the Zsh Development Group have been advised of
19 * the possibility of such damage.
21 * Peter Stephenson and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose. The software
24 * provided hereunder is on an "as is" basis, and Peter Stephenson and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
30 #include "mathfunc.mdh"
31 #include "mathfunc.pro"
85 /* also functions taking a string argument */
92 * also to do, but differently argument or returned: abs (no type
96 /* Flags for bounds. Note these must start at 1, not 0. */
99 BF_POS
= 1, /* must be positive */
100 BF_NONNEG
= 2, /* must be non-negative */
101 BF_FRAC
= 3, /* must be -1 <= x <= 1 */
102 BF_GE1
= 4, /* must be >= 1 */
103 BF_FRACO
= 5, /* must be in open range -1 < x < 1 */
104 BF_INTPOS
= 6, /* must be non-integer or positive */
105 BF_GTRM1
= 7, /* must be > -1 */
106 BF_NONZ
= 8, /* must be nonzero */
107 BF_POS2
= 9 /* second argument must be positive */
110 #define BFLAG(x) ((x) << 8)
113 * Flags for type of function: unlike the above, these must
114 * be individually bit-testable.
118 TF_NOCONV
= 1, /* don't convert to float */
119 TF_INT1
= 2, /* first argument is integer */
120 TF_INT2
= 4, /* second argument is integer */
121 TF_NOASS
= 8 /* don't assign result as double */
124 #define TFLAG(x) ((x) << 16)
127 static struct mathfunc mftab
[] = {
128 NUMMATHFUNC("abs", math_func
, 1, 1, MF_ABS
| BFLAG(BF_FRAC
) |
129 TFLAG(TF_NOCONV
|TF_NOASS
)),
130 NUMMATHFUNC("acos", math_func
, 1, 1, MF_ACOS
| BFLAG(BF_FRAC
)),
131 NUMMATHFUNC("acosh", math_func
, 1, 1, MF_ACOSH
| BFLAG(BF_GE1
)),
132 NUMMATHFUNC("asin", math_func
, 1, 1, MF_ASIN
| BFLAG(BF_FRAC
)),
133 NUMMATHFUNC("asinh", math_func
, 1, 1, MF_ASINH
),
134 NUMMATHFUNC("atan", math_func
, 1, 2, MF_ATAN
),
135 NUMMATHFUNC("atanh", math_func
, 1, 1, MF_ATANH
| BFLAG(BF_FRACO
)),
136 NUMMATHFUNC("cbrt", math_func
, 1, 1, MF_CBRT
),
137 NUMMATHFUNC("ceil", math_func
, 1, 1, MF_CEIL
),
138 NUMMATHFUNC("copysign", math_func
, 2, 2, MF_COPYSIGN
),
139 NUMMATHFUNC("cos", math_func
, 1, 1, MF_COS
),
140 NUMMATHFUNC("cosh", math_func
, 1, 1, MF_COSH
),
141 NUMMATHFUNC("erf", math_func
, 1, 1, MF_ERF
),
142 NUMMATHFUNC("erfc", math_func
, 1, 1, MF_ERFC
),
143 NUMMATHFUNC("exp", math_func
, 1, 1, MF_EXP
),
144 NUMMATHFUNC("expm1", math_func
, 1, 1, MF_EXPM1
),
145 NUMMATHFUNC("fabs", math_func
, 1, 1, MF_FABS
),
146 NUMMATHFUNC("float", math_func
, 1, 1, MF_FLOAT
),
147 NUMMATHFUNC("floor", math_func
, 1, 1, MF_FLOOR
),
148 NUMMATHFUNC("fmod", math_func
, 2, 2, MF_FMOD
),
149 NUMMATHFUNC("gamma", math_func
, 1, 1, MF_GAMMA
| BFLAG(BF_INTPOS
)),
150 NUMMATHFUNC("hypot", math_func
, 2, 2, MF_HYPOT
),
151 NUMMATHFUNC("ilogb", math_func
, 1, 1, MF_ILOGB
| BFLAG(BF_NONZ
) |
153 NUMMATHFUNC("int", math_func
, 1, 1, MF_INT
| TFLAG(TF_NOASS
)),
154 NUMMATHFUNC("j0", math_func
, 1, 1, MF_J0
),
155 NUMMATHFUNC("j1", math_func
, 1, 1, MF_J1
),
156 NUMMATHFUNC("jn", math_func
, 2, 2, MF_JN
| TFLAG(TF_INT1
)),
157 NUMMATHFUNC("ldexp", math_func
, 2, 2, MF_LDEXP
| TFLAG(TF_INT2
)),
158 NUMMATHFUNC("lgamma", math_func
, 1, 1, MF_LGAMMA
| BFLAG(BF_INTPOS
)),
159 NUMMATHFUNC("log", math_func
, 1, 1, MF_LOG
| BFLAG(BF_POS
)),
160 NUMMATHFUNC("log10", math_func
, 1, 1, MF_LOG10
| BFLAG(BF_POS
)),
161 NUMMATHFUNC("log1p", math_func
, 1, 1, MF_LOG1P
| BFLAG(BF_GTRM1
)),
162 NUMMATHFUNC("logb", math_func
, 1, 1, MF_LOGB
| BFLAG(BF_NONZ
)),
163 NUMMATHFUNC("nextafter", math_func
, 2, 2, MF_NEXTAFTER
),
165 STRMATHFUNC("rand48", math_string
, MS_RAND48
),
167 NUMMATHFUNC("rint", math_func
, 1, 1, MF_RINT
),
168 NUMMATHFUNC("scalb", math_func
, 2, 2, MF_SCALB
| TFLAG(TF_INT2
)),
170 NUMMATHFUNC("signgam", math_func
, 0, 0, MF_SIGNGAM
| TFLAG(TF_NOASS
)),
172 NUMMATHFUNC("sin", math_func
, 1, 1, MF_SIN
),
173 NUMMATHFUNC("sinh", math_func
, 1, 1, MF_SINH
),
174 NUMMATHFUNC("sqrt", math_func
, 1, 1, MF_SQRT
| BFLAG(BF_NONNEG
)),
175 NUMMATHFUNC("tan", math_func
, 1, 1, MF_TAN
),
176 NUMMATHFUNC("tanh", math_func
, 1, 1, MF_TANH
),
177 NUMMATHFUNC("y0", math_func
, 1, 1, MF_Y0
| BFLAG(BF_POS
)),
178 NUMMATHFUNC("y1", math_func
, 1, 1, MF_Y1
| BFLAG(BF_POS
)),
179 NUMMATHFUNC("yn", math_func
, 2, 2, MF_YN
| BFLAG(BF_POS2
) | TFLAG(TF_INT1
))
184 math_func(char *name
, int argc
, mnumber
*argv
, int id
)
187 double argd
= 0, argd2
= 0, retd
= 0;
190 if (argc
&& !(id
& TFLAG(TF_NOCONV
))) {
191 if (id
& TFLAG(TF_INT1
))
192 argi
= (argv
->type
== MN_FLOAT
) ? (zlong
)argv
->u
.d
: argv
->u
.l
;
194 argd
= (argv
->type
== MN_INTEGER
) ? (double)argv
->u
.l
: argv
->u
.d
;
196 if (id
& TFLAG(TF_INT2
))
197 argi
= (argv
[1].type
== MN_FLOAT
) ? (zlong
)argv
[1].u
.d
:
200 argd2
= (argv
[1].type
== MN_INTEGER
) ? (double)argv
[1].u
.l
:
214 switch ((id
>> 8) & 0xff) {
216 rtst
= (argd
<= 0.0);
224 rtst
= (fabs(argd
) > 1.0);
232 rtst
= (fabs(argd
) >= 1.0);
236 rtst
= (argd
<= 0 && (double)(zlong
)argd
== argd
);
244 rtst
= (argd2
<= 0.0);
249 zerr("math: argument to %s out of range", name
);
256 ret
.type
= argv
->type
;
257 if (argv
->type
== MN_INTEGER
)
258 ret
.u
.l
= (argv
->u
.l
< 0) ? - argv
->u
.l
: argv
->u
.l
;
260 ret
.u
.d
= fabs(argv
->u
.d
);
281 retd
= atan2(argd
, argd2
);
299 retd
= copysign(argd
, argd2
);
339 retd
= fmod(argd
, argd2
);
347 retd
= hypot(argd
, argd2
);
351 ret
.type
= MN_INTEGER
;
352 ret
.u
.l
= ilogb(argd
);
356 ret
.type
= MN_INTEGER
;
357 ret
.u
.l
= (zlong
)argd
;
369 retd
= jn(argi
, argd2
);
373 retd
= ldexp(argd
, argi
);
397 retd
= nextafter(argd
, argd2
);
405 retd
= scalb(argd
, argi
);
410 ret
.type
= MN_INTEGER
;
444 retd
= yn(argi
, argd2
);
449 fprintf(stderr
, "BUG: mathfunc type not handled: %d", id
);
454 if (!(id
& TFLAG(TF_NOASS
)))
462 math_string(UNUSED(char *name
), char *arg
, int id
)
464 mnumber ret
= zero_mnumber
;
467 * Post-process the string argument, which is just passed verbatim.
468 * Not clear if any other functions that use math_string() will
469 * want this, but assume so for now.
473 send
= arg
+ strlen(arg
);
474 while (send
> arg
&& iblank(send
[-1]))
483 static unsigned short seedbuf
[3];
484 static int seedbuf_init
;
485 unsigned short tmp_seedbuf
[3], *seedbufptr
;
489 /* Seed is contained in parameter named by arg */
491 seedbufptr
= tmp_seedbuf
;
492 if ((seedstr
= getsparam(arg
)) && strlen(seedstr
) >= 12) {
496 * Decode three sets of four hex digits corresponding
497 * to each unsigned short.
499 for (i
= 0; i
< 3 && !do_init
; i
++) {
500 unsigned short *seedptr
= seedbufptr
+ i
;
502 for (j
= 0; j
< 4; j
++) {
503 if (idigit(*seedstr
))
504 *seedptr
+= *seedstr
- '0';
505 else if (tolower(*seedstr
) >= 'a' &&
506 tolower(*seedstr
) <= 'f')
507 *seedptr
+= tolower(*seedstr
) - 'a' + 10;
523 /* Use default seed: must be initialised. */
524 seedbufptr
= seedbuf
;
531 seedbufptr
[0] = (unsigned short)rand();
532 seedbufptr
[1] = (unsigned short)rand();
533 seedbufptr
[2] = (unsigned short)rand();
535 * Some implementations of rand48() need initialization.
536 * This is likely to be harmless elsewhere, since
537 * according to the documentation erand48() normally
538 * doesn't look at the seed set in this way.
540 (void)seed48(seedbufptr
);
543 ret
.u
.d
= erand48(seedbufptr
);
548 sprintf(outbuf
, "%04x%04x%04x", (int)seedbufptr
[0],
549 (int)seedbufptr
[1], (int)seedbufptr
[2]);
550 setsparam(arg
, ztrdup(outbuf
));
561 static struct features module_features
= {
564 mftab
, sizeof(mftab
)/sizeof(*mftab
),
571 setup_(UNUSED(Module m
))
578 features_(Module m
, char ***features
)
580 *features
= featuresarray(m
, &module_features
);
586 enables_(Module m
, int **enables
)
588 return handlefeatures(m
, &module_features
, enables
);
602 return setfeatureenables(m
, &module_features
, NULL
);
607 finish_(UNUSED(Module m
))