| 1 | /* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved. |
| 2 | Distributed by Free Software Foundation, Inc. |
| 3 | |
| 4 | This file is part of Ghostscript. |
| 5 | |
| 6 | Ghostscript is distributed in the hope that it will be useful, but |
| 7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility |
| 8 | to anyone for the consequences of using it or for whether it serves any |
| 9 | particular purpose or works at all, unless he says so in writing. Refer |
| 10 | to the Ghostscript General Public License for full details. |
| 11 | |
| 12 | Everyone is granted permission to copy, modify and redistribute |
| 13 | Ghostscript, but only under the conditions described in the Ghostscript |
| 14 | General Public License. A copy of this license is supposed to have been |
| 15 | given to you along with Ghostscript so you can know your rights and |
| 16 | responsibilities. It should be in a file named COPYING. Among other |
| 17 | things, the copyright notice and this notice must be preserved on all |
| 18 | copies. */ |
| 19 | |
| 20 | /* zmath.c */ |
| 21 | /* Mathematical 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 | /* Factors for converting between degrees and radians */ |
| 29 | double degrees_to_radians = M_PI / 180.0; |
| 30 | double radians_to_degrees = 180.0 / M_PI; |
| 31 | |
| 32 | /* Current state of random number generator. */ |
| 33 | /* We have to implement this ourselves because */ |
| 34 | /* the Unix rand doesn't provide anything equivalent to rrand. */ |
| 35 | private long rand_state; |
| 36 | |
| 37 | /* Initialize the random number generator. */ |
| 38 | private void |
| 39 | zmath_init() |
| 40 | { rand_state = 1; |
| 41 | } |
| 42 | |
| 43 | /****** NOTE: none of these operators currently ******/ |
| 44 | /****** check for floating over- or underflow. ******/ |
| 45 | |
| 46 | /* sqrt */ |
| 47 | int |
| 48 | zsqrt(register os_ptr op) |
| 49 | { float num; |
| 50 | int code = num_params(op, 1, &num); |
| 51 | if ( code < 0 ) return code; |
| 52 | if ( num < 0.0 ) return e_rangecheck; |
| 53 | make_real(op, sqrt(num)); |
| 54 | return 0; |
| 55 | } |
| 56 | |
| 57 | /* arccos */ |
| 58 | int |
| 59 | zarccos(register os_ptr op) |
| 60 | { float num, result; |
| 61 | int code = num_params(op, 1, &num); |
| 62 | if ( code < 0 ) return code; |
| 63 | result = acos(num) * radians_to_degrees; |
| 64 | make_real(op, result); |
| 65 | return 0; |
| 66 | } |
| 67 | |
| 68 | /* arcsin */ |
| 69 | int |
| 70 | zarcsin(register os_ptr op) |
| 71 | { float num, result; |
| 72 | int code = num_params(op, 1, &num); |
| 73 | if ( code < 0 ) return code; |
| 74 | result = asin(num) * radians_to_degrees; |
| 75 | make_real(op, result); |
| 76 | return 0; |
| 77 | } |
| 78 | |
| 79 | /* atan */ |
| 80 | int |
| 81 | zatan(register os_ptr op) |
| 82 | { float args[2]; |
| 83 | float result; |
| 84 | int code = num_params(op, 2, args); |
| 85 | if ( code < 0 ) return code; |
| 86 | if ( args[0] == 0 ) /* on X-axis, special case */ |
| 87 | { if ( args[1] == 0 ) return e_undefinedresult; |
| 88 | result = (args[1] < 0 ? 180 : 0); |
| 89 | } |
| 90 | else |
| 91 | { result = atan2(args[0], args[1]) * radians_to_degrees; |
| 92 | if ( result < 0 ) result += 360; |
| 93 | } |
| 94 | make_real(op - 1, result); |
| 95 | pop(1); |
| 96 | return 0; |
| 97 | } |
| 98 | |
| 99 | /* cos */ |
| 100 | int |
| 101 | zcos(register os_ptr op) |
| 102 | { float angle; |
| 103 | int code = num_params(op, 1, &angle); |
| 104 | if ( code < 0 ) return code; |
| 105 | make_real(op, cos(angle * degrees_to_radians)); |
| 106 | return 0; |
| 107 | } |
| 108 | |
| 109 | /* sin */ |
| 110 | int |
| 111 | zsin(register os_ptr op) |
| 112 | { float angle; |
| 113 | int code = num_params(op, 1, &angle); |
| 114 | if ( code < 0 ) return code; |
| 115 | make_real(op, sin(angle * degrees_to_radians)); |
| 116 | return 0; |
| 117 | } |
| 118 | |
| 119 | /* exp */ |
| 120 | int |
| 121 | zexp(register os_ptr op) |
| 122 | { float args[2]; |
| 123 | float result; |
| 124 | double ipart; |
| 125 | int code = num_params(op, 2, args); |
| 126 | if ( code < 0 ) return code; |
| 127 | if ( args[0] == 0.0 && args[1] == 0.0 ) return e_undefinedresult; |
| 128 | if ( args[0] < 0.0 && modf(args[1], &ipart) != 0.0 ) |
| 129 | return e_undefinedresult; |
| 130 | result = pow(args[0], args[1]); |
| 131 | make_real(op - 1, result); |
| 132 | pop(1); |
| 133 | return 0; |
| 134 | } |
| 135 | |
| 136 | /* ln */ |
| 137 | int |
| 138 | zln(register os_ptr op) |
| 139 | { float num; |
| 140 | int code = num_params(op, 1, &num); |
| 141 | if ( code < 0 ) return code; |
| 142 | if ( num <= 0.0 ) return e_rangecheck; |
| 143 | make_real(op, log(num)); |
| 144 | return 0; |
| 145 | } |
| 146 | |
| 147 | /* log */ |
| 148 | int |
| 149 | zlog(register os_ptr op) |
| 150 | { float num; |
| 151 | int code = num_params(op, 1, &num); |
| 152 | if ( code < 0 ) return code; |
| 153 | if ( num <= 0.0 ) return e_rangecheck; |
| 154 | make_real(op, log10(num)); |
| 155 | return 0; |
| 156 | } |
| 157 | |
| 158 | /* rand */ |
| 159 | int |
| 160 | zrand(register os_ptr op) |
| 161 | { /* |
| 162 | * We use an algorithm from CACM 31 no. 10, pp. 1192-1201, |
| 163 | * October 1988. According to a posting by Ed Taft on |
| 164 | * comp.lang.postscript, Level 2 (Adobe) PostScript interpreters use |
| 165 | * this algorithm too: |
| 166 | * x[n+1] = (16807 * x[n]) mod (2^31 - 1) |
| 167 | */ |
| 168 | #define A 16807 |
| 169 | #define M 0x7fffffff |
| 170 | #define Q 127773 /* M / A */ |
| 171 | #define R 2836 /* M % A */ |
| 172 | rand_state = A * (rand_state % Q) - R * (rand_state / Q); |
| 173 | while ( rand_state <= 0 ) rand_state += M; |
| 174 | #undef A |
| 175 | #undef M |
| 176 | #undef Q |
| 177 | #undef R |
| 178 | push(1); |
| 179 | make_int(op, rand_state); |
| 180 | return 0; |
| 181 | } |
| 182 | |
| 183 | /* srand */ |
| 184 | int |
| 185 | zsrand(register os_ptr op) |
| 186 | { check_type(*op, t_integer); |
| 187 | rand_state = op->value.intval; |
| 188 | pop(1); |
| 189 | return 0; |
| 190 | } |
| 191 | |
| 192 | /* rrand */ |
| 193 | int |
| 194 | zrrand(register os_ptr op) |
| 195 | { push(1); |
| 196 | make_int(op, rand_state); |
| 197 | return 0; |
| 198 | } |
| 199 | |
| 200 | /* ------ Initialization procedure ------ */ |
| 201 | |
| 202 | op_def zmath_op_defs[] = { |
| 203 | {"1arccos", zarccos}, /* extension */ |
| 204 | {"1arcsin", zarcsin}, /* extension */ |
| 205 | {"2atan", zatan}, |
| 206 | {"1cos", zcos}, |
| 207 | {"2exp", zexp}, |
| 208 | {"1ln", zln}, |
| 209 | {"1log", zlog}, |
| 210 | {"0rand", zrand}, |
| 211 | {"0rrand", zrrand}, |
| 212 | {"1sin", zsin}, |
| 213 | {"1sqrt", zsqrt}, |
| 214 | {"1srand", zsrand}, |
| 215 | op_def_end(zmath_init) |
| 216 | }; |