386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / zarith.c
CommitLineData
eb2698b9
WJ
1/* Copyright (C) 1989, 1990, 1991 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
19
20/* zarith.c */
21/* Arithmetic operators for GhostScript */
22#include "math_.h"
23#include "ghost.h"
24#include "errors.h"
25#include "oper.h"
26#include "store.h"
27
28/****** NOTE: none of the arithmetic operators ******/
29/****** currently check for floating exceptions ******/
30
31/* Imported operators */
32extern int zcvi(P1(os_ptr));
33
34/* Macro for accessing next-to-top stack element */
35#define opm1 (op-1)
36/* Macros for generating non-integer cases for arithmetic operations. */
37/* 'frob' is one of the arithmetic operators, +, -, or *. */
38#define non_int_cases(frob,frob_equals)\
39 switch ( r_type(op) ) {\
40 default: return e_typecheck;\
41 case t_real: switch ( r_type(opm1) ) {\
42 default: return e_typecheck;\
43 case t_real: op[-1].value.realval frob_equals op->value.realval; break;\
44 case t_integer: make_real(opm1, op[-1].value.intval frob op->value.realval);\
45 } break;\
46 case t_integer: switch ( r_type(opm1) ) {\
47 default: return e_typecheck;\
48 case t_real: op[-1].value.realval frob_equals op->value.intval; break;\
49 case t_integer:
50#define end_cases()\
51 } }
52
53/* add */
54/* We make this into a separate procedure because */
55/* the interpreter will almost always call it directly. */
56int
57zop_add(register os_ptr op)
58{ non_int_cases(+, +=)
59 { long int2 = op->value.intval;
60 if ( ((op[-1].value.intval += int2) ^ int2) < 0 &&
61 ((op[-1].value.intval - int2) ^ int2) >= 0
62 )
63 { /* Overflow, convert to real */
64 make_real(opm1, (float)(op[-1].value.intval - int2) + int2);
65 }
66 }
67 end_cases()
68 return 0;
69}
70int
71zadd(os_ptr op)
72{ int code = zop_add(op);
73 if ( code == 0 ) { pop(1); }
74 return code;
75}
76
77/* div */
78int
79zdiv(register os_ptr op)
80{ register os_ptr op1 = op - 1;
81 /* We can't use the non_int_cases macro, */
82 /* because we have to check explicitly for op == 0. */
83 switch ( r_type(op) )
84 {
85 default: return e_typecheck;
86 case t_real:
87 if ( op->value.realval == 0 ) return e_undefinedresult;
88 switch ( r_type(op1) )
89 {
90 default: return e_typecheck;
91 case t_real: op1->value.realval /= op->value.realval; break;
92 case t_integer: make_real(op1, op1->value.intval / op->value.realval);
93 }
94 break;
95 case t_integer:
96 if ( op->value.intval == 0 ) return e_undefinedresult;
97 switch ( r_type(op1) )
98 {
99 default: return e_typecheck;
100 case t_real: op1->value.realval /= op->value.intval; break;
101 case t_integer: make_real(op1, (float)op1->value.intval / op->value.intval);
102 }
103 }
104 pop(1);
105 return 0;
106}
107
108/* mul */
109int
110zmul(register os_ptr op)
111{ non_int_cases(*, *=)
112 { long int1 = op[-1].value.intval;
113 long int2 = op->value.intval;
114 long abs1 = (int1 >= 0 ? int1 : - int1);
115 long abs2 = (int2 >= 0 ? int2 : - int2);
116 float fprod;
117 if ( (abs1 > 0x7fff || abs2 > 0x7fff) &&
118 /* At least one of the operands is very large. */
119 /* Check for integer overflow. */
120 abs1 != 0 &&
121 abs2 > 0x7fffffffL / abs1 &&
122 /* Check for the boundary case */
123 (fprod = (float)int1 * int2,
124 (int1 * int2 != -0x80000000L ||
125 fprod != (float)-0x80000000L))
126 )
127 make_real(opm1, fprod);
128 else
129 op[-1].value.intval = int1 * int2;
130 }
131 end_cases()
132 pop(1);
133 return 0;
134}
135
136/* sub */
137/* We make this into a separate procedure because */
138/* the interpreter will almost always call it directly. */
139int
140zop_sub(register os_ptr op)
141{ non_int_cases(-, -=)
142 { long int1 = op[-1].value.intval;
143 if ( (int1 ^ (op[-1].value.intval = int1 - op->value.intval)) < 0 &&
144 (int1 ^ op->value.intval) < 0
145 )
146 { /* Overflow, convert to real */
147 make_real(opm1, (float)int1 - op->value.intval);
148 }
149 }
150 end_cases()
151 return 0;
152}
153int
154zsub(os_ptr op)
155{ int code = zop_sub(op);
156 if ( code == 0 ) { pop(1); }
157 return code;
158}
159
160/* idiv */
161int
162zidiv(register os_ptr op)
163{ /* The Red Book says this only works on integers, */
164 /* but implementations also accept reals. */
165 ref save_num;
166 int code;
167 save_num = op[-1];
168 code = zdiv(op);
169 if ( code < 0 ) return code; /* division failed */
170 code = zcvi(op - 1);
171 if ( code < 0 )
172 { /* cvi failed, restore numerator */
173 op[-1] = save_num;
174 osp = op; /* restore osp as well */
175 }
176 return code;
177}
178
179/* mod */
180int
181zmod(register os_ptr op)
182{ check_type(op[-1], t_integer);
183 check_type(*op, t_integer);
184 if ( op->value.intval == 0 ) return e_undefinedresult;
185 op[-1].value.intval %= op->value.intval;
186 pop(1);
187 return 0;
188}
189
190/* neg */
191int
192zneg(register os_ptr op)
193{ switch ( r_type(op) )
194 {
195 default: return e_typecheck;
196 case t_real: op->value.realval = -op->value.realval; break;
197 case t_integer:
198 if ( op->value.intval == -0x80000000L ) /* min integer */
199 make_real(op, -(float)-0x80000000L);
200 else
201 op->value.intval = -op->value.intval;
202 }
203 return 0;
204}
205
206/* ceiling */
207int
208zceiling(register os_ptr op)
209{ switch ( r_type(op) )
210 {
211 default: return e_typecheck;
212 case t_real: op->value.realval = ceil(op->value.realval);
213 case t_integer: ;
214 }
215 return 0;
216}
217
218/* floor */
219int
220zfloor(register os_ptr op)
221{ switch ( r_type(op) )
222 {
223 default: return e_typecheck;
224 case t_real: op->value.realval = floor(op->value.realval);
225 case t_integer: ;
226 }
227 return 0;
228}
229
230/* round */
231int
232zround(register os_ptr op)
233{ switch ( r_type(op) )
234 {
235 default: return e_typecheck;
236 case t_real: op->value.realval = floor(op->value.realval + 0.5);
237 case t_integer: ;
238 }
239 return 0;
240}
241
242/* truncate */
243int
244ztruncate(register os_ptr op)
245{ switch ( r_type(op) )
246 {
247 default: return e_typecheck;
248 case t_real:
249 op->value.realval =
250 (op->value.realval < 0.0 ?
251 ceil(op->value.realval) :
252 floor(op->value.realval));
253 case t_integer: ;
254 }
255 return 0;
256}
257
258/* ------ Initialization table ------ */
259
260op_def zarith_op_defs[] = {
261 {"2add", zadd},
262 {"1ceiling", zceiling},
263 {"2div", zdiv},
264 {"2idiv", zidiv},
265 {"1floor", zfloor},
266 {"2mod", zmod},
267 {"2mul", zmul},
268 {"1neg", zneg},
269 {"1round", zround},
270 {"2sub", zsub},
271 {"1truncate", ztruncate},
272 op_def_end(0)
273};