Coverage Report

Created: 2025-06-10 06:59

/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
37.1k
#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
15.5k
{
51
15.5k
    os_ptr op = osp;
52
15.5k
    double num;
53
15.5k
    int code;
54
55
15.5k
    check_op(1);
56
15.5k
    code = real_param(op, &num);
57
58
15.5k
    if (code < 0)
59
0
        return code;
60
15.5k
    if (num < 0.0)
61
1
        return_error(gs_error_rangecheck);
62
15.5k
    make_real(op, sqrt(num));
63
15.5k
    return 0;
64
15.5k
}
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
42
{
112
42
    os_ptr op = osp;
113
42
    double args[2];
114
42
    double result;
115
42
    int code;
116
117
42
    check_op(2);
118
42
    code = num_params(op, 2, args);
119
120
42
    if (code < 0)
121
0
        return code;
122
42
    code = gs_atan2_degrees(args[0], args[1], &result);
123
42
    if (code < 0)
124
0
        return code;
125
42
    make_real(op - 1, result);
126
42
    pop(1);
127
42
    return 0;
128
42
}
129
130
/* <num> cos <real> */
131
int
132
zcos(i_ctx_t *i_ctx_p)
133
333k
{
134
333k
    os_ptr op = osp;
135
333k
    double angle;
136
333k
    int code;
137
138
333k
    check_op(1);
139
333k
    code = real_param(op, &angle);
140
141
333k
    if (code < 0)
142
0
        return code;
143
333k
    make_real(op, gs_cos_degrees(angle));
144
333k
    return 0;
145
333k
}
146
147
/* <num> sin <real> */
148
int
149
zsin(i_ctx_t *i_ctx_p)
150
977
{
151
977
    os_ptr op = osp;
152
977
    double angle;
153
977
    int code;
154
977
    check_op(1);
155
976
    code = real_param(op, &angle);
156
157
976
    if (code < 0)
158
1
        return code;
159
975
    make_real(op, gs_sin_degrees(angle));
160
975
    return 0;
161
976
}
162
163
/* <base> <exponent> exp <real> */
164
int
165
zexp(i_ctx_t *i_ctx_p)
166
6
{
167
6
    os_ptr op = osp;
168
6
    double args[2];
169
6
    double result;
170
6
    double ipart;
171
6
    int code;
172
173
6
    check_op(2);
174
5
    code = num_params(op, 2, args);
175
176
5
    if (code < 0)
177
0
        return code;
178
5
    if (args[0] == 0.0 && args[1] < 0)
179
0
        return_error(gs_error_undefinedresult);
180
5
    if (args[0] < 0.0 && modf(args[1], &ipart) != 0.0)
181
0
        return_error(gs_error_undefinedresult);
182
5
    if (args[0] == 0.0 && args[1] == 0.0)
183
1
        result = 1.0;    /* match Adobe; can't rely on C library */
184
4
    else
185
4
        result = pow(args[0], args[1]);
186
5
#ifdef HAVE_ISINF
187
5
    if (isinf(result))
188
0
        return_error(gs_error_undefinedresult);
189
5
#endif
190
5
    make_real(op - 1, result);
191
5
    pop(1);
192
5
    return 0;
193
5
}
194
195
/* <posnum> ln <real> */
196
int
197
zln(i_ctx_t *i_ctx_p)
198
21
{
199
21
    os_ptr op = osp;
200
21
    double num;
201
21
    int code;
202
203
21
    check_op(1);
204
20
    code = real_param(op, &num);
205
206
20
    if (code < 0)
207
1
        return code;
208
19
    if (num <= 0.0)
209
1
        return_error(gs_error_rangecheck);
210
18
    make_real(op, log(num));
211
18
    return 0;
212
19
}
213
214
/* <posnum> log <real> */
215
int
216
zlog(i_ctx_t *i_ctx_p)
217
2
{
218
2
    os_ptr op = osp;
219
2
    double num;
220
2
    int code;
221
222
2
    check_op(1);
223
2
    code = real_param(op, &num);
224
225
2
    if (code < 0)
226
1
        return code;
227
1
    if (num <= 0.0)
228
0
        return_error(gs_error_rangecheck);
229
1
    make_real(op, log10(num));
230
1
    return 0;
231
1
}
232
233
/* - rand <int> */
234
static int
235
zrand(i_ctx_t *i_ctx_p)
236
8.90k
{
237
8.90k
    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
8.90k
#define A 16807
247
8.90k
#define M 0x7fffffff
248
17.8k
#define Q 127773    /* M / A */
249
8.90k
#define R 2836      /* M % A */
250
8.90k
    zrand_state = A * (zrand_state % Q) - R * (zrand_state / Q);
251
    /* Note that zrand_state cannot be 0 here. */
252
8.90k
    if (zrand_state <= 0)
253
138
        zrand_state += M;
254
8.90k
#undef A
255
8.90k
#undef M
256
8.90k
#undef Q
257
8.90k
#undef R
258
8.90k
    push(1);
259
8.90k
    make_int(op, zrand_state);
260
8.90k
    return 0;
261
8.90k
}
262
263
/* <int> srand - */
264
static int
265
zsrand(i_ctx_t *i_ctx_p)
266
1.41k
{
267
1.41k
    os_ptr op = osp;
268
1.41k
    int state;
269
270
1.41k
    check_op(1);
271
1.41k
    check_type(*op, t_integer);
272
1.41k
    state = op->value.intval;
273
    /*
274
     * The following somewhat bizarre adjustments are according to
275
     * public information from Adobe describing their implementation.
276
     */
277
1.41k
    if (state < 1)
278
26
        state = -(state % 0x7ffffffe) + 1;
279
1.39k
    else if (state > 0x7ffffffe)
280
0
        state = 0x7ffffffe;
281
1.41k
    zrand_state = state;
282
1.41k
    pop(1);
283
1.41k
    return 0;
284
1.41k
}
285
286
/* - rrand <int> */
287
static int
288
zrrand(i_ctx_t *i_ctx_p)
289
2
{
290
2
    os_ptr op = osp;
291
292
2
    push(1);
293
2
    make_int(op, zrand_state);
294
2
    return 0;
295
2
}
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
};