Coverage Report

Created: 2025-06-10 07:06

/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
5
#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
4
{
51
4
    os_ptr op = osp;
52
4
    double num;
53
4
    int code;
54
55
4
    check_op(1);
56
3
    code = real_param(op, &num);
57
58
3
    if (code < 0)
59
0
        return code;
60
3
    if (num < 0.0)
61
1
        return_error(gs_error_rangecheck);
62
2
    make_real(op, sqrt(num));
63
2
    return 0;
64
3
}
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
0
{
112
0
    os_ptr op = osp;
113
0
    double args[2];
114
0
    double result;
115
0
    int code;
116
117
0
    check_op(2);
118
0
    code = num_params(op, 2, args);
119
120
0
    if (code < 0)
121
0
        return code;
122
0
    code = gs_atan2_degrees(args[0], args[1], &result);
123
0
    if (code < 0)
124
0
        return code;
125
0
    make_real(op - 1, result);
126
0
    pop(1);
127
0
    return 0;
128
0
}
129
130
/* <num> cos <real> */
131
int
132
zcos(i_ctx_t *i_ctx_p)
133
1.45M
{
134
1.45M
    os_ptr op = osp;
135
1.45M
    double angle;
136
1.45M
    int code;
137
138
1.45M
    check_op(1);
139
1.45M
    code = real_param(op, &angle);
140
141
1.45M
    if (code < 0)
142
0
        return code;
143
1.45M
    make_real(op, gs_cos_degrees(angle));
144
1.45M
    return 0;
145
1.45M
}
146
147
/* <num> sin <real> */
148
int
149
zsin(i_ctx_t *i_ctx_p)
150
1
{
151
1
    os_ptr op = osp;
152
1
    double angle;
153
1
    int code;
154
1
    check_op(1);
155
0
    code = real_param(op, &angle);
156
157
0
    if (code < 0)
158
0
        return code;
159
0
    make_real(op, gs_sin_degrees(angle));
160
0
    return 0;
161
0
}
162
163
/* <base> <exponent> exp <real> */
164
int
165
zexp(i_ctx_t *i_ctx_p)
166
2
{
167
2
    os_ptr op = osp;
168
2
    double args[2];
169
2
    double result;
170
2
    double ipart;
171
2
    int code;
172
173
2
    check_op(2);
174
1
    code = num_params(op, 2, args);
175
176
1
    if (code < 0)
177
1
        return code;
178
0
    if (args[0] == 0.0 && args[1] < 0)
179
0
        return_error(gs_error_undefinedresult);
180
0
    if (args[0] < 0.0 && modf(args[1], &ipart) != 0.0)
181
0
        return_error(gs_error_undefinedresult);
182
0
    if (args[0] == 0.0 && args[1] == 0.0)
183
0
        result = 1.0;   /* match Adobe; can't rely on C library */
184
0
    else
185
0
        result = pow(args[0], args[1]);
186
0
#ifdef HAVE_ISINF
187
0
    if (isinf(result))
188
0
        return_error(gs_error_undefinedresult);
189
0
#endif
190
0
    make_real(op - 1, result);
191
0
    pop(1);
192
0
    return 0;
193
0
}
194
195
/* <posnum> ln <real> */
196
int
197
zln(i_ctx_t *i_ctx_p)
198
2
{
199
2
    os_ptr op = osp;
200
2
    double num;
201
2
    int code;
202
203
2
    check_op(1);
204
1
    code = real_param(op, &num);
205
206
1
    if (code < 0)
207
1
        return code;
208
0
    if (num <= 0.0)
209
0
        return_error(gs_error_rangecheck);
210
0
    make_real(op, log(num));
211
0
    return 0;
212
0
}
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
1
    code = real_param(op, &num);
224
225
1
    if (code < 0)
226
0
        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
1
{
237
1
    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
1
#define A 16807
247
1
#define M 0x7fffffff
248
2
#define Q 127773    /* M / A */
249
1
#define R 2836      /* M % A */
250
1
    zrand_state = A * (zrand_state % Q) - R * (zrand_state / Q);
251
    /* Note that zrand_state cannot be 0 here. */
252
1
    if (zrand_state <= 0)
253
0
        zrand_state += M;
254
1
#undef A
255
1
#undef M
256
1
#undef Q
257
1
#undef R
258
1
    push(1);
259
1
    make_int(op, zrand_state);
260
1
    return 0;
261
1
}
262
263
/* <int> srand - */
264
static int
265
zsrand(i_ctx_t *i_ctx_p)
266
2
{
267
2
    os_ptr op = osp;
268
2
    int state;
269
270
2
    check_op(1);
271
1
    check_type(*op, t_integer);
272
1
    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
    if (state < 1)
278
0
        state = -(state % 0x7ffffffe) + 1;
279
1
    else if (state > 0x7ffffffe)
280
0
        state = 0x7ffffffe;
281
1
    zrand_state = state;
282
1
    pop(1);
283
1
    return 0;
284
1
}
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
};