Coverage Report

Created: 2025-06-24 07:01

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