Coverage Report

Created: 2025-06-10 07:19

/src/ghostpdl/psi/zmath.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Mathematical operators */
18
#include "math_.h"
19
#include "ghost.h"
20
#include "gxfarith.h"
21
#include "oper.h"
22
#include "store.h"
23
24
/*
25
 * Many of the procedures in this file are public only so they can be
26
 * called from the FunctionType 4 interpreter (zfunc4.c).
27
 */
28
29
/*
30
 * Define the current state of random number generator for operators.  We
31
 * have to implement this ourselves because the Unix rand doesn't provide
32
 * anything equivalent to rrand.  Note that the value always lies in the
33
 * range [0..0x7ffffffe], even if longs are longer than 32 bits.
34
 *
35
 * The state must be public so that context switching can save and
36
 * restore it.  (Even though the Red Book doesn't mention this,
37
 * we verified with Adobe that this is the case.)
38
 */
39
16.9M
#define zrand_state (i_ctx_p->rand_state)
40
41
/* Initialize the random number generator. */
42
const long rand_state_initial = 1;
43
44
/****** NOTE: none of these operators currently ******/
45
/****** check for floating over- or underflow.  ******/
46
47
/* <num> sqrt <real> */
48
int
49
zsqrt(i_ctx_t *i_ctx_p)
50
105k
{
51
105k
    os_ptr op = osp;
52
105k
    double num;
53
105k
    int code;
54
55
105k
    check_op(1);
56
105k
    code = real_param(op, &num);
57
58
105k
    if (code < 0)
59
0
        return code;
60
105k
    if (num < 0.0)
61
0
        return_error(gs_error_rangecheck);
62
105k
    make_real(op, sqrt(num));
63
105k
    return 0;
64
105k
}
65
66
/* <num> arccos <real> */
67
static int
68
zarccos(i_ctx_t *i_ctx_p)
69
0
{
70
0
    os_ptr op = osp;
71
0
    double num, result;
72
0
    int code;
73
74
0
    check_op(1);
75
0
    code = real_param(op, &num);
76
77
0
    if (code < 0)
78
0
        return code;
79
0
    if (num < -1 || num > 1)
80
0
        return_error(gs_error_rangecheck);
81
82
0
    result = acos(num) * radians_to_degrees;
83
0
    make_real(op, result);
84
0
    return 0;
85
0
}
86
87
/* <num> arcsin <real> */
88
static int
89
zarcsin(i_ctx_t *i_ctx_p)
90
0
{
91
0
    os_ptr op = osp;
92
0
    double num, result;
93
0
    int code;
94
95
0
    check_op(1);
96
0
    code = real_param(op, &num);
97
98
0
    if (code < 0)
99
0
        return code;
100
0
    if (num < -1 || num > 1)
101
0
        return_error(gs_error_rangecheck);
102
103
0
    result = asin(num) * radians_to_degrees;
104
0
    make_real(op, result);
105
0
    return 0;
106
0
}
107
108
/* <num> <denom> atan <real> */
109
int
110
zatan(i_ctx_t *i_ctx_p)
111
69
{
112
69
    os_ptr op = osp;
113
69
    double args[2];
114
69
    double result;
115
69
    int code;
116
117
69
    check_op(2);
118
69
    code = num_params(op, 2, args);
119
120
69
    if (code < 0)
121
1
        return code;
122
68
    code = gs_atan2_degrees(args[0], args[1], &result);
123
68
    if (code < 0)
124
0
        return code;
125
68
    make_real(op - 1, result);
126
68
    pop(1);
127
68
    return 0;
128
68
}
129
130
/* <num> cos <real> */
131
int
132
zcos(i_ctx_t *i_ctx_p)
133
7.23M
{
134
7.23M
    os_ptr op = osp;
135
7.23M
    double angle;
136
7.23M
    int code;
137
138
7.23M
    check_op(1);
139
7.23M
    code = real_param(op, &angle);
140
141
7.23M
    if (code < 0)
142
0
        return code;
143
7.23M
    make_real(op, gs_cos_degrees(angle));
144
7.23M
    return 0;
145
7.23M
}
146
147
/* <num> sin <real> */
148
int
149
zsin(i_ctx_t *i_ctx_p)
150
19.1k
{
151
19.1k
    os_ptr op = osp;
152
19.1k
    double angle;
153
19.1k
    int code;
154
19.1k
    check_op(1);
155
19.1k
    code = real_param(op, &angle);
156
157
19.1k
    if (code < 0)
158
0
        return code;
159
19.1k
    make_real(op, gs_sin_degrees(angle));
160
19.1k
    return 0;
161
19.1k
}
162
163
/* <base> <exponent> exp <real> */
164
int
165
zexp(i_ctx_t *i_ctx_p)
166
2.43M
{
167
2.43M
    os_ptr op = osp;
168
2.43M
    double args[2];
169
2.43M
    double result;
170
2.43M
    double ipart;
171
2.43M
    int code;
172
173
2.43M
    check_op(2);
174
2.43M
    code = num_params(op, 2, args);
175
176
2.43M
    if (code < 0)
177
0
        return code;
178
2.43M
    if (args[0] == 0.0 && args[1] < 0)
179
0
        return_error(gs_error_undefinedresult);
180
2.43M
    if (args[0] < 0.0 && modf(args[1], &ipart) != 0.0)
181
0
        return_error(gs_error_undefinedresult);
182
2.43M
    if (args[0] == 0.0 && args[1] == 0.0)
183
0
        result = 1.0;   /* match Adobe; can't rely on C library */
184
2.43M
    else
185
2.43M
        result = pow(args[0], args[1]);
186
2.43M
#ifdef HAVE_ISINF
187
2.43M
    if (isinf(result))
188
0
        return_error(gs_error_undefinedresult);
189
2.43M
#endif
190
2.43M
    make_real(op - 1, result);
191
2.43M
    pop(1);
192
2.43M
    return 0;
193
2.43M
}
194
195
/* <posnum> ln <real> */
196
int
197
zln(i_ctx_t *i_ctx_p)
198
5
{
199
5
    os_ptr op = osp;
200
5
    double num;
201
5
    int code;
202
203
5
    check_op(1);
204
4
    code = real_param(op, &num);
205
206
4
    if (code < 0)
207
1
        return code;
208
3
    if (num <= 0.0)
209
0
        return_error(gs_error_rangecheck);
210
3
    make_real(op, log(num));
211
3
    return 0;
212
3
}
213
214
/* <posnum> log <real> */
215
int
216
zlog(i_ctx_t *i_ctx_p)
217
1
{
218
1
    os_ptr op = osp;
219
1
    double num;
220
1
    int code;
221
222
1
    check_op(1);
223
0
    code = real_param(op, &num);
224
225
0
    if (code < 0)
226
0
        return code;
227
0
    if (num <= 0.0)
228
0
        return_error(gs_error_rangecheck);
229
0
    make_real(op, log10(num));
230
0
    return 0;
231
0
}
232
233
/* - rand <int> */
234
static int
235
zrand(i_ctx_t *i_ctx_p)
236
4.19M
{
237
4.19M
    os_ptr op = osp;
238
239
        /*
240
         * We use an algorithm from CACM 31 no. 10, pp. 1192-1201,
241
         * October 1988.  According to a posting by Ed Taft on
242
         * comp.lang.postscript, Level 2 (Adobe) PostScript interpreters
243
         * use this algorithm too:
244
         *      x[n+1] = (16807 * x[n]) mod (2^31 - 1)
245
         */
246
4.19M
#define A 16807
247
4.19M
#define M 0x7fffffff
248
8.38M
#define Q 127773    /* M / A */
249
4.19M
#define R 2836      /* M % A */
250
4.19M
    zrand_state = A * (zrand_state % Q) - R * (zrand_state / Q);
251
    /* Note that zrand_state cannot be 0 here. */
252
4.19M
    if (zrand_state <= 0)
253
47.2k
        zrand_state += M;
254
4.19M
#undef A
255
4.19M
#undef M
256
4.19M
#undef Q
257
4.19M
#undef R
258
4.19M
    push(1);
259
4.19M
    make_int(op, zrand_state);
260
4.19M
    return 0;
261
4.19M
}
262
263
/* <int> srand - */
264
static int
265
zsrand(i_ctx_t *i_ctx_p)
266
120k
{
267
120k
    os_ptr op = osp;
268
120k
    int state;
269
270
120k
    check_op(1);
271
120k
    check_type(*op, t_integer);
272
120k
    state = op->value.intval;
273
    /*
274
     * The following somewhat bizarre adjustments are according to
275
     * public information from Adobe describing their implementation.
276
     */
277
120k
    if (state < 1)
278
94.3k
        state = -(state % 0x7ffffffe) + 1;
279
25.7k
    else if (state > 0x7ffffffe)
280
0
        state = 0x7ffffffe;
281
120k
    zrand_state = state;
282
120k
    pop(1);
283
120k
    return 0;
284
120k
}
285
286
/* - rrand <int> */
287
static int
288
zrrand(i_ctx_t *i_ctx_p)
289
0
{
290
0
    os_ptr op = osp;
291
292
0
    push(1);
293
0
    make_int(op, zrand_state);
294
0
    return 0;
295
0
}
296
297
/* ------ Initialization procedure ------ */
298
299
const op_def zmath_op_defs[] =
300
{
301
    {"1arccos", zarccos}, /* extension */
302
    {"1arcsin", zarcsin}, /* extension */
303
    {"2atan", zatan},
304
    {"1cos", zcos},
305
    {"2exp", zexp},
306
    {"1ln", zln},
307
    {"1log", zlog},
308
    {"0rand", zrand},
309
    {"0rrand", zrrand},
310
    {"1sin", zsin},
311
    {"1sqrt", zsqrt},
312
    {"1srand", zsrand},
313
    op_def_end(0)
314
};