Commit | Line | Data |
---|---|---|
198b5bf9 C |
1 | /* |
2 | * Copyright (c) 1994 David I. Bell | |
3 | * Permission is granted to use, distribute, or modify this source, | |
4 | * provided that this copyright notice remains intact. | |
5 | * | |
6 | * Generic value manipulation routines. | |
7 | */ | |
8 | ||
9 | #include "value.h" | |
10 | #include "opcodes.h" | |
11 | #include "func.h" | |
12 | #include "symbol.h" | |
13 | #include "string.h" | |
14 | ||
15 | ||
16 | /* | |
17 | * Free a value and set its type to undefined. | |
18 | */ | |
19 | void | |
20 | freevalue(vp) | |
21 | register VALUE *vp; /* value to be freed */ | |
22 | { | |
23 | int type; /* type of value being freed */ | |
24 | ||
25 | type = vp->v_type; | |
26 | vp->v_type = V_NULL; | |
27 | switch (type) { | |
28 | case V_NULL: | |
29 | case V_ADDR: | |
30 | case V_FILE: | |
31 | break; | |
32 | case V_STR: | |
33 | if (vp->v_subtype == V_STRALLOC) | |
34 | free(vp->v_str); | |
35 | break; | |
36 | case V_NUM: | |
37 | qfree(vp->v_num); | |
38 | break; | |
39 | case V_COM: | |
40 | comfree(vp->v_com); | |
41 | break; | |
42 | case V_MAT: | |
43 | matfree(vp->v_mat); | |
44 | break; | |
45 | case V_LIST: | |
46 | listfree(vp->v_list); | |
47 | break; | |
48 | case V_ASSOC: | |
49 | assocfree(vp->v_assoc); | |
50 | break; | |
51 | case V_OBJ: | |
52 | objfree(vp->v_obj); | |
53 | break; | |
54 | default: | |
55 | math_error("Freeing unknown value type"); | |
56 | } | |
57 | vp->v_subtype = V_NOSUBTYPE; | |
58 | } | |
59 | ||
60 | ||
61 | /* | |
62 | * Copy a value from one location to another. | |
63 | * This overwrites the specified new value without checking it. | |
64 | */ | |
65 | void | |
66 | copyvalue(oldvp, newvp) | |
67 | register VALUE *oldvp; /* value to be copied from */ | |
68 | register VALUE *newvp; /* value to be copied into */ | |
69 | { | |
70 | newvp->v_type = V_NULL; | |
71 | switch (oldvp->v_type) { | |
72 | case V_NULL: | |
73 | break; | |
74 | case V_FILE: | |
75 | newvp->v_file = oldvp->v_file; | |
76 | break; | |
77 | case V_NUM: | |
78 | newvp->v_num = qlink(oldvp->v_num); | |
79 | break; | |
80 | case V_COM: | |
81 | newvp->v_com = clink(oldvp->v_com); | |
82 | break; | |
83 | case V_STR: | |
84 | newvp->v_str = oldvp->v_str; | |
85 | if (oldvp->v_subtype == V_STRALLOC) { | |
86 | newvp->v_str = (char *)malloc(strlen(oldvp->v_str) + 1); | |
87 | if (newvp->v_str == NULL) | |
88 | math_error("Cannot get memory for string copy"); | |
89 | strcpy(newvp->v_str, oldvp->v_str); | |
90 | } | |
91 | break; | |
92 | case V_MAT: | |
93 | newvp->v_mat = matcopy(oldvp->v_mat); | |
94 | break; | |
95 | case V_LIST: | |
96 | newvp->v_list = listcopy(oldvp->v_list); | |
97 | break; | |
98 | case V_ASSOC: | |
99 | newvp->v_assoc = assoccopy(oldvp->v_assoc); | |
100 | break; | |
101 | case V_ADDR: | |
102 | newvp->v_addr = oldvp->v_addr; | |
103 | break; | |
104 | case V_OBJ: | |
105 | newvp->v_obj = objcopy(oldvp->v_obj); | |
106 | break; | |
107 | default: | |
108 | math_error("Copying unknown value type"); | |
109 | } | |
110 | if (oldvp->v_type == V_STR) { | |
111 | newvp->v_subtype = oldvp->v_subtype; | |
112 | } else { | |
113 | newvp->v_subtype = V_NOSUBTYPE; | |
114 | } | |
115 | newvp->v_type = oldvp->v_type; | |
116 | ||
117 | } | |
118 | ||
119 | ||
120 | /* | |
121 | * Negate an arbitrary value. | |
122 | * Result is placed in the indicated location. | |
123 | */ | |
124 | void | |
125 | negvalue(vp, vres) | |
126 | VALUE *vp, *vres; | |
127 | { | |
128 | vres->v_type = V_NULL; | |
129 | switch (vp->v_type) { | |
130 | case V_NUM: | |
131 | vres->v_num = qneg(vp->v_num); | |
132 | vres->v_type = V_NUM; | |
133 | return; | |
134 | case V_COM: | |
135 | vres->v_com = cneg(vp->v_com); | |
136 | vres->v_type = V_COM; | |
137 | return; | |
138 | case V_MAT: | |
139 | vres->v_mat = matneg(vp->v_mat); | |
140 | vres->v_type = V_MAT; | |
141 | return; | |
142 | case V_OBJ: | |
143 | *vres = objcall(OBJ_NEG, vp, NULL_VALUE, NULL_VALUE); | |
144 | return; | |
145 | default: | |
146 | math_error("Illegal value for negation"); | |
147 | } | |
148 | } | |
149 | ||
150 | ||
151 | /* | |
152 | * Add two arbitrary values together. | |
153 | * Result is placed in the indicated location. | |
154 | */ | |
155 | void | |
156 | addvalue(v1, v2, vres) | |
157 | VALUE *v1, *v2, *vres; | |
158 | { | |
159 | COMPLEX *c; | |
160 | ||
161 | vres->v_type = V_NULL; | |
162 | switch (TWOVAL(v1->v_type, v2->v_type)) { | |
163 | case TWOVAL(V_NUM, V_NUM): | |
164 | vres->v_num = qadd(v1->v_num, v2->v_num); | |
165 | vres->v_type = V_NUM; | |
166 | return; | |
167 | case TWOVAL(V_COM, V_NUM): | |
168 | vres->v_com = caddq(v1->v_com, v2->v_num); | |
169 | vres->v_type = V_COM; | |
170 | return; | |
171 | case TWOVAL(V_NUM, V_COM): | |
172 | vres->v_com = caddq(v2->v_com, v1->v_num); | |
173 | vres->v_type = V_COM; | |
174 | return; | |
175 | case TWOVAL(V_COM, V_COM): | |
176 | vres->v_com = cadd(v1->v_com, v2->v_com); | |
177 | vres->v_type = V_COM; | |
178 | c = vres->v_com; | |
179 | if (!cisreal(c)) | |
180 | return; | |
181 | vres->v_num = qlink(c->real); | |
182 | vres->v_type = V_NUM; | |
183 | comfree(c); | |
184 | return; | |
185 | case TWOVAL(V_MAT, V_MAT): | |
186 | vres->v_mat = matadd(v1->v_mat, v2->v_mat); | |
187 | vres->v_type = V_MAT; | |
188 | return; | |
189 | default: | |
190 | if ((v1->v_type != V_OBJ) && (v2->v_type != V_OBJ)) | |
191 | math_error("Non-compatible values for add"); | |
192 | *vres = objcall(OBJ_ADD, v1, v2, NULL_VALUE); | |
193 | return; | |
194 | } | |
195 | } | |
196 | ||
197 | ||
198 | /* | |
199 | * Subtract one arbitrary value from another one. | |
200 | * Result is placed in the indicated location. | |
201 | */ | |
202 | void | |
203 | subvalue(v1, v2, vres) | |
204 | VALUE *v1, *v2, *vres; | |
205 | { | |
206 | COMPLEX *c; | |
207 | ||
208 | vres->v_type = V_NULL; | |
209 | switch (TWOVAL(v1->v_type, v2->v_type)) { | |
210 | case TWOVAL(V_NUM, V_NUM): | |
211 | vres->v_num = qsub(v1->v_num, v2->v_num); | |
212 | vres->v_type = V_NUM; | |
213 | return; | |
214 | case TWOVAL(V_COM, V_NUM): | |
215 | vres->v_com = csubq(v1->v_com, v2->v_num); | |
216 | vres->v_type = V_COM; | |
217 | return; | |
218 | case TWOVAL(V_NUM, V_COM): | |
219 | c = csubq(v2->v_com, v1->v_num); | |
220 | vres->v_com = cneg(c); | |
221 | comfree(c); | |
222 | vres->v_type = V_COM; | |
223 | return; | |
224 | case TWOVAL(V_COM, V_COM): | |
225 | vres->v_com = csub(v1->v_com, v2->v_com); | |
226 | vres->v_type = V_COM; | |
227 | c = vres->v_com; | |
228 | if (!cisreal(c)) | |
229 | return; | |
230 | vres->v_num = qlink(c->real); | |
231 | vres->v_type = V_NUM; | |
232 | comfree(c); | |
233 | return; | |
234 | case TWOVAL(V_MAT, V_MAT): | |
235 | vres->v_mat = matsub(v1->v_mat, v2->v_mat); | |
236 | vres->v_type = V_MAT; | |
237 | return; | |
238 | default: | |
239 | if ((v1->v_type != V_OBJ) && (v2->v_type != V_OBJ)) | |
240 | math_error("Non-compatible values for subtract"); | |
241 | *vres = objcall(OBJ_SUB, v1, v2, NULL_VALUE); | |
242 | return; | |
243 | } | |
244 | } | |
245 | ||
246 | ||
247 | /* | |
248 | * Multiply two arbitrary values together. | |
249 | * Result is placed in the indicated location. | |
250 | */ | |
251 | void | |
252 | mulvalue(v1, v2, vres) | |
253 | VALUE *v1, *v2, *vres; | |
254 | { | |
255 | COMPLEX *c; | |
256 | ||
257 | vres->v_type = V_NULL; | |
258 | switch (TWOVAL(v1->v_type, v2->v_type)) { | |
259 | case TWOVAL(V_NUM, V_NUM): | |
260 | vres->v_num = qmul(v1->v_num, v2->v_num); | |
261 | vres->v_type = V_NUM; | |
262 | return; | |
263 | case TWOVAL(V_COM, V_NUM): | |
264 | vres->v_com = cmulq(v1->v_com, v2->v_num); | |
265 | vres->v_type = V_COM; | |
266 | break; | |
267 | case TWOVAL(V_NUM, V_COM): | |
268 | vres->v_com = cmulq(v2->v_com, v1->v_num); | |
269 | vres->v_type = V_COM; | |
270 | break; | |
271 | case TWOVAL(V_COM, V_COM): | |
272 | vres->v_com = cmul(v1->v_com, v2->v_com); | |
273 | vres->v_type = V_COM; | |
274 | break; | |
275 | case TWOVAL(V_MAT, V_MAT): | |
276 | vres->v_mat = matmul(v1->v_mat, v2->v_mat); | |
277 | vres->v_type = V_MAT; | |
278 | return; | |
279 | case TWOVAL(V_MAT, V_NUM): | |
280 | case TWOVAL(V_MAT, V_COM): | |
281 | vres->v_mat = matmulval(v1->v_mat, v2); | |
282 | vres->v_type = V_MAT; | |
283 | return; | |
284 | case TWOVAL(V_NUM, V_MAT): | |
285 | case TWOVAL(V_COM, V_MAT): | |
286 | vres->v_mat = matmulval(v2->v_mat, v1); | |
287 | vres->v_type = V_MAT; | |
288 | return; | |
289 | default: | |
290 | if ((v1->v_type != V_OBJ) && (v2->v_type != V_OBJ)) | |
291 | math_error("Non-compatible values for multiply"); | |
292 | *vres = objcall(OBJ_MUL, v1, v2, NULL_VALUE); | |
293 | return; | |
294 | } | |
295 | c = vres->v_com; | |
296 | if (cisreal(c)) { | |
297 | vres->v_num = qlink(c->real); | |
298 | vres->v_type = V_NUM; | |
299 | comfree(c); | |
300 | } | |
301 | } | |
302 | ||
303 | ||
304 | /* | |
305 | * Square an arbitrary value. | |
306 | * Result is placed in the indicated location. | |
307 | */ | |
308 | void | |
309 | squarevalue(vp, vres) | |
310 | VALUE *vp, *vres; | |
311 | { | |
312 | COMPLEX *c; | |
313 | ||
314 | vres->v_type = V_NULL; | |
315 | switch (vp->v_type) { | |
316 | case V_NUM: | |
317 | vres->v_num = qsquare(vp->v_num); | |
318 | vres->v_type = V_NUM; | |
319 | return; | |
320 | case V_COM: | |
321 | vres->v_com = csquare(vp->v_com); | |
322 | vres->v_type = V_COM; | |
323 | c = vres->v_com; | |
324 | if (!cisreal(c)) | |
325 | return; | |
326 | vres->v_num = qlink(c->real); | |
327 | vres->v_type = V_NUM; | |
328 | comfree(c); | |
329 | return; | |
330 | case V_MAT: | |
331 | vres->v_mat = matsquare(vp->v_mat); | |
332 | vres->v_type = V_MAT; | |
333 | return; | |
334 | case V_OBJ: | |
335 | *vres = objcall(OBJ_SQUARE, vp, NULL_VALUE, NULL_VALUE); | |
336 | return; | |
337 | default: | |
338 | math_error("Illegal value for squaring"); | |
339 | } | |
340 | } | |
341 | ||
342 | ||
343 | /* | |
344 | * Invert an arbitrary value. | |
345 | * Result is placed in the indicated location. | |
346 | */ | |
347 | void | |
348 | invertvalue(vp, vres) | |
349 | VALUE *vp, *vres; | |
350 | { | |
351 | vres->v_type = V_NULL; | |
352 | switch (vp->v_type) { | |
353 | case V_NUM: | |
354 | vres->v_num = qinv(vp->v_num); | |
355 | vres->v_type = V_NUM; | |
356 | return; | |
357 | case V_COM: | |
358 | vres->v_com = cinv(vp->v_com); | |
359 | vres->v_type = V_COM; | |
360 | return; | |
361 | case V_MAT: | |
362 | vres->v_mat = matinv(vp->v_mat); | |
363 | vres->v_type = V_MAT; | |
364 | return; | |
365 | case V_OBJ: | |
366 | *vres = objcall(OBJ_INV, vp, NULL_VALUE, NULL_VALUE); | |
367 | return; | |
368 | default: | |
369 | math_error("Illegal value for inverting"); | |
370 | } | |
371 | } | |
372 | ||
373 | ||
374 | /* | |
375 | * Round an arbitrary value to the specified number of decimal places. | |
376 | * Result is placed in the indicated location. | |
377 | */ | |
378 | void | |
379 | roundvalue(v1, v2, vres) | |
380 | VALUE *v1, *v2, *vres; | |
381 | { | |
382 | long places = -1; | |
383 | NUMBER *q; | |
384 | COMPLEX *c; | |
385 | ||
386 | switch (v2->v_type) { | |
387 | case V_NUM: | |
388 | q = v2->v_num; | |
389 | if (qisfrac(q) || zisbig(q->num)) | |
390 | math_error("Bad number of places for round"); | |
391 | places = qtoi(q); | |
392 | break; | |
393 | case V_INT: | |
394 | places = v2->v_int; | |
395 | break; | |
396 | default: | |
397 | math_error("Bad value type for places in round"); | |
398 | } | |
399 | if (places < 0) | |
400 | math_error("Negative number of places in round"); | |
401 | vres->v_type = V_NULL; | |
402 | switch (v1->v_type) { | |
403 | case V_NUM: | |
404 | if (qisint(v1->v_num)) | |
405 | vres->v_num = qlink(v1->v_num); | |
406 | else | |
407 | vres->v_num = qround(v1->v_num, places); | |
408 | vres->v_type = V_NUM; | |
409 | return; | |
410 | case V_COM: | |
411 | if (cisint(v1->v_com)) { | |
412 | vres->v_com = clink(v1->v_com); | |
413 | vres->v_type = V_COM; | |
414 | return; | |
415 | } | |
416 | vres->v_com = cround(v1->v_com, places); | |
417 | vres->v_type = V_COM; | |
418 | c = vres->v_com; | |
419 | if (cisreal(c)) { | |
420 | vres->v_num = qlink(c->real); | |
421 | vres->v_type = V_NUM; | |
422 | comfree(c); | |
423 | } | |
424 | return; | |
425 | case V_MAT: | |
426 | vres->v_mat = matround(v1->v_mat, places); | |
427 | vres->v_type = V_MAT; | |
428 | return; | |
429 | case V_OBJ: | |
430 | *vres = objcall(OBJ_ROUND, v1, v2, NULL_VALUE); | |
431 | return; | |
432 | default: | |
433 | math_error("Illegal value for round"); | |
434 | } | |
435 | } | |
436 | ||
437 | ||
438 | /* | |
439 | * Round an arbitrary value to the specified number of binary places. | |
440 | * Result is placed in the indicated location. | |
441 | */ | |
442 | void | |
443 | broundvalue(v1, v2, vres) | |
444 | VALUE *v1, *v2, *vres; | |
445 | { | |
446 | long places = -1; | |
447 | NUMBER *q; | |
448 | COMPLEX *c; | |
449 | ||
450 | switch (v2->v_type) { | |
451 | case V_NUM: | |
452 | q = v2->v_num; | |
453 | if (qisfrac(q) || zisbig(q->num)) | |
454 | math_error("Bad number of places for bround"); | |
455 | places = qtoi(q); | |
456 | break; | |
457 | case V_INT: | |
458 | places = v2->v_int; | |
459 | break; | |
460 | default: | |
461 | math_error("Bad value type for places in bround"); | |
462 | } | |
463 | if (places < 0) | |
464 | math_error("Negative number of places in bround"); | |
465 | vres->v_type = V_NULL; | |
466 | switch (v1->v_type) { | |
467 | case V_NUM: | |
468 | if (qisint(v1->v_num)) | |
469 | vres->v_num = qlink(v1->v_num); | |
470 | else | |
471 | vres->v_num = qbround(v1->v_num, places); | |
472 | vres->v_type = V_NUM; | |
473 | return; | |
474 | case V_COM: | |
475 | if (cisint(v1->v_com)) { | |
476 | vres->v_com = clink(v1->v_com); | |
477 | vres->v_type = V_COM; | |
478 | return; | |
479 | } | |
480 | vres->v_com = cbround(v1->v_com, places); | |
481 | vres->v_type = V_COM; | |
482 | c = vres->v_com; | |
483 | if (cisreal(c)) { | |
484 | vres->v_num = qlink(c->real); | |
485 | vres->v_type = V_NUM; | |
486 | comfree(c); | |
487 | } | |
488 | return; | |
489 | case V_MAT: | |
490 | vres->v_mat = matbround(v1->v_mat, places); | |
491 | vres->v_type = V_MAT; | |
492 | return; | |
493 | case V_OBJ: | |
494 | *vres = objcall(OBJ_BROUND, v1, v2, NULL_VALUE); | |
495 | return; | |
496 | default: | |
497 | math_error("Illegal value for bround"); | |
498 | } | |
499 | } | |
500 | ||
501 | ||
502 | /* | |
503 | * Take the integer part of an arbitrary value. | |
504 | * Result is placed in the indicated location. | |
505 | */ | |
506 | void | |
507 | intvalue(vp, vres) | |
508 | VALUE *vp, *vres; | |
509 | { | |
510 | COMPLEX *c; | |
511 | ||
512 | vres->v_type = V_NULL; | |
513 | switch (vp->v_type) { | |
514 | case V_NUM: | |
515 | if (qisint(vp->v_num)) | |
516 | vres->v_num = qlink(vp->v_num); | |
517 | else | |
518 | vres->v_num = qint(vp->v_num); | |
519 | vres->v_type = V_NUM; | |
520 | return; | |
521 | case V_COM: | |
522 | if (cisint(vp->v_com)) { | |
523 | vres->v_com = clink(vp->v_com); | |
524 | vres->v_type = V_COM; | |
525 | return; | |
526 | } | |
527 | vres->v_com = cint(vp->v_com); | |
528 | vres->v_type = V_COM; | |
529 | c = vres->v_com; | |
530 | if (cisreal(c)) { | |
531 | vres->v_num = qlink(c->real); | |
532 | vres->v_type = V_NUM; | |
533 | comfree(c); | |
534 | } | |
535 | return; | |
536 | case V_MAT: | |
537 | vres->v_mat = matint(vp->v_mat); | |
538 | vres->v_type = V_MAT; | |
539 | return; | |
540 | case V_OBJ: | |
541 | *vres = objcall(OBJ_INT, vp, NULL_VALUE, NULL_VALUE); | |
542 | return; | |
543 | default: | |
544 | math_error("Illegal value for int"); | |
545 | } | |
546 | } | |
547 | ||
548 | ||
549 | /* | |
550 | * Take the fractional part of an arbitrary value. | |
551 | * Result is placed in the indicated location. | |
552 | */ | |
553 | void | |
554 | fracvalue(vp, vres) | |
555 | VALUE *vp, *vres; | |
556 | { | |
557 | vres->v_type = V_NULL; | |
558 | switch (vp->v_type) { | |
559 | case V_NUM: | |
560 | if (qisint(vp->v_num)) | |
561 | vres->v_num = qlink(&_qzero_); | |
562 | else | |
563 | vres->v_num = qfrac(vp->v_num); | |
564 | vres->v_type = V_NUM; | |
565 | return; | |
566 | case V_COM: | |
567 | if (cisint(vp->v_com)) { | |
568 | vres->v_num = clink(&_qzero_); | |
569 | vres->v_type = V_NUM; | |
570 | return; | |
571 | } | |
572 | vres->v_com = cfrac(vp->v_com); | |
573 | vres->v_type = V_COM; | |
574 | return; | |
575 | case V_MAT: | |
576 | vres->v_mat = matfrac(vp->v_mat); | |
577 | vres->v_type = V_MAT; | |
578 | return; | |
579 | case V_OBJ: | |
580 | *vres = objcall(OBJ_FRAC, vp, NULL_VALUE, NULL_VALUE); | |
581 | return; | |
582 | default: | |
583 | math_error("Illegal value for frac function"); | |
584 | } | |
585 | } | |
586 | ||
587 | ||
588 | /* | |
589 | * Increment an arbitrary value by one. | |
590 | * Result is placed in the indicated location. | |
591 | */ | |
592 | void | |
593 | incvalue(vp, vres) | |
594 | VALUE *vp, *vres; | |
595 | { | |
596 | switch (vp->v_type) { | |
597 | case V_NUM: | |
598 | vres->v_num = qinc(vp->v_num); | |
599 | vres->v_type = V_NUM; | |
600 | return; | |
601 | case V_COM: | |
602 | vres->v_com = caddq(vp->v_com, &_qone_); | |
603 | vres->v_type = V_COM; | |
604 | return; | |
605 | case V_OBJ: | |
606 | *vres = objcall(OBJ_INC, vp, NULL_VALUE, NULL_VALUE); | |
607 | return; | |
608 | default: | |
609 | math_error("Illegal value for incrementing"); | |
610 | } | |
611 | } | |
612 | ||
613 | ||
614 | /* | |
615 | * Decrement an arbitrary value by one. | |
616 | * Result is placed in the indicated location. | |
617 | */ | |
618 | void | |
619 | decvalue(vp, vres) | |
620 | VALUE *vp, *vres; | |
621 | { | |
622 | switch (vp->v_type) { | |
623 | case V_NUM: | |
624 | vres->v_num = qdec(vp->v_num); | |
625 | vres->v_type = V_NUM; | |
626 | return; | |
627 | case V_COM: | |
628 | vres->v_com = caddq(vp->v_com, &_qnegone_); | |
629 | vres->v_type = V_COM; | |
630 | return; | |
631 | case V_OBJ: | |
632 | *vres = objcall(OBJ_DEC, vp, NULL_VALUE, NULL_VALUE); | |
633 | return; | |
634 | default: | |
635 | math_error("Illegal value for decrementing"); | |
636 | } | |
637 | } | |
638 | ||
639 | ||
640 | /* | |
641 | * Produce the 'conjugate' of an arbitrary value. | |
642 | * Result is placed in the indicated location. | |
643 | * (Example: complex conjugate.) | |
644 | */ | |
645 | void | |
646 | conjvalue(vp, vres) | |
647 | VALUE *vp, *vres; | |
648 | { | |
649 | vres->v_type = V_NULL; | |
650 | switch (vp->v_type) { | |
651 | case V_NUM: | |
652 | vres->v_num = qlink(vp->v_num); | |
653 | vres->v_type = V_NUM; | |
654 | return; | |
655 | case V_COM: | |
656 | vres->v_com = comalloc(); | |
657 | vres->v_com->real = qlink(vp->v_com->real); | |
658 | vres->v_com->imag = qneg(vp->v_com->imag); | |
659 | vres->v_type = V_COM; | |
660 | return; | |
661 | case V_MAT: | |
662 | vres->v_mat = matconj(vp->v_mat); | |
663 | vres->v_type = V_MAT; | |
664 | return; | |
665 | case V_OBJ: | |
666 | *vres = objcall(OBJ_CONJ, vp, NULL_VALUE, NULL_VALUE); | |
667 | return; | |
668 | default: | |
669 | math_error("Illegal value for conjugation"); | |
670 | } | |
671 | } | |
672 | ||
673 | ||
674 | /* | |
675 | * Take the square root of an arbitrary value within the specified error. | |
676 | * Result is placed in the indicated location. | |
677 | */ | |
678 | void | |
679 | sqrtvalue(v1, v2, vres) | |
680 | VALUE *v1, *v2, *vres; | |
681 | { | |
682 | NUMBER *q, *tmp; | |
683 | COMPLEX *c; | |
684 | ||
685 | if (v2->v_type != V_NUM) | |
686 | math_error("Non-real epsilon for sqrt"); | |
687 | q = v2->v_num; | |
688 | if (qisneg(q) || qiszero(q)) | |
689 | math_error("Illegal epsilon value for sqrt"); | |
690 | switch (v1->v_type) { | |
691 | case V_NUM: | |
692 | if (!qisneg(v1->v_num)) { | |
693 | vres->v_num = qsqrt(v1->v_num, q); | |
694 | vres->v_type = V_NUM; | |
695 | return; | |
696 | } | |
697 | tmp = qneg(v1->v_num); | |
698 | c = comalloc(); | |
699 | c->imag = qsqrt(tmp, q); | |
700 | qfree(tmp); | |
701 | vres->v_com = c; | |
702 | vres->v_type = V_COM; | |
703 | break; | |
704 | case V_COM: | |
705 | vres->v_com = csqrt(v1->v_com, q); | |
706 | vres->v_type = V_COM; | |
707 | break; | |
708 | case V_OBJ: | |
709 | *vres = objcall(OBJ_SQRT, v1, v2, NULL_VALUE); | |
710 | return; | |
711 | default: | |
712 | math_error("Bad value for taking square root"); | |
713 | } | |
714 | c = vres->v_com; | |
715 | if (cisreal(c)) { | |
716 | vres->v_num = qlink(c->real); | |
717 | vres->v_type = V_NUM; | |
718 | comfree(c); | |
719 | } | |
720 | } | |
721 | ||
722 | ||
723 | /* | |
724 | * Take the Nth root of an arbitrary value within the specified error. | |
725 | * Result is placed in the indicated location. | |
726 | */ | |
727 | void | |
728 | rootvalue(v1, v2, v3, vres) | |
729 | VALUE *v1; /* value to take root of */ | |
730 | VALUE *v2; /* value specifying root to take */ | |
731 | VALUE *v3; /* value specifying error */ | |
732 | VALUE *vres; | |
733 | { | |
734 | NUMBER *q1, *q2; | |
735 | COMPLEX ctmp; | |
736 | ||
737 | if ((v2->v_type != V_NUM) || (v3->v_type != V_NUM)) | |
738 | math_error("Non-real arguments for root"); | |
739 | q1 = v2->v_num; | |
740 | q2 = v3->v_num; | |
741 | if (qisneg(q1) || qiszero(q1) || qisfrac(q1)) | |
742 | math_error("Non-positive or non-integral root"); | |
743 | if (qisneg(q2) || qiszero(q2)) | |
744 | math_error("Non-positive epsilon for root"); | |
745 | switch (v1->v_type) { | |
746 | case V_NUM: | |
747 | if (!qisneg(v1->v_num) || zisodd(q1->num)) { | |
748 | vres->v_num = qroot(v1->v_num, q1, q2); | |
749 | vres->v_type = V_NUM; | |
750 | return; | |
751 | } | |
752 | ctmp.real = v1->v_num; | |
753 | ctmp.imag = &_qzero_; | |
754 | ctmp.links = 1; | |
755 | vres->v_com = croot(&ctmp, q1, q2); | |
756 | vres->v_type = V_COM; | |
757 | return; | |
758 | case V_COM: | |
759 | vres->v_com = croot(v1->v_com, q1, q2); | |
760 | vres->v_type = V_COM; | |
761 | return; | |
762 | case V_OBJ: | |
763 | *vres = objcall(OBJ_ROOT, v1, v2, v3); | |
764 | return; | |
765 | default: | |
766 | math_error("Taking root of bad value"); | |
767 | } | |
768 | } | |
769 | ||
770 | ||
771 | /* | |
772 | * Take the absolute value of an arbitrary value within the specified error. | |
773 | * Result is placed in the indicated location. | |
774 | */ | |
775 | void | |
776 | absvalue(v1, v2, vres) | |
777 | VALUE *v1, *v2, *vres; | |
778 | { | |
779 | static NUMBER *q; | |
780 | NUMBER *epsilon; | |
781 | ||
782 | if (v2->v_type != V_NUM) | |
783 | math_error("Bad epsilon type for abs"); | |
784 | epsilon = v2->v_num; | |
785 | if (qiszero(epsilon) || qisneg(epsilon)) | |
786 | math_error("Non-positive epsilon for abs"); | |
787 | switch (v1->v_type) { | |
788 | case V_NUM: | |
789 | if (qisneg(v1->v_num)) | |
790 | q = qneg(v1->v_num); | |
791 | else | |
792 | q = qlink(v1->v_num); | |
793 | break; | |
794 | case V_COM: | |
795 | q = qhypot(v1->v_com->real, v1->v_com->imag, epsilon); | |
796 | break; | |
797 | case V_OBJ: | |
798 | *vres = objcall(OBJ_ABS, v1, v2, NULL_VALUE); | |
799 | return; | |
800 | default: | |
801 | math_error("Illegal value for absolute value"); | |
802 | } | |
803 | vres->v_num = q; | |
804 | vres->v_type = V_NUM; | |
805 | } | |
806 | ||
807 | ||
808 | /* | |
809 | * Calculate the norm of an arbitrary value. | |
810 | * Result is placed in the indicated location. | |
811 | * The norm is the square of the absolute value. | |
812 | */ | |
813 | void | |
814 | normvalue(vp, vres) | |
815 | VALUE *vp, *vres; | |
816 | { | |
817 | NUMBER *q1, *q2; | |
818 | ||
819 | vres->v_type = V_NULL; | |
820 | switch (vp->v_type) { | |
821 | case V_NUM: | |
822 | vres->v_num = qsquare(vp->v_num); | |
823 | vres->v_type = V_NUM; | |
824 | return; | |
825 | case V_COM: | |
826 | q1 = qsquare(vp->v_com->real); | |
827 | q2 = qsquare(vp->v_com->imag); | |
828 | vres->v_num = qadd(q1, q2); | |
829 | vres->v_type = V_NUM; | |
830 | qfree(q1); | |
831 | qfree(q2); | |
832 | return; | |
833 | case V_OBJ: | |
834 | *vres = objcall(OBJ_NORM, vp, NULL_VALUE, NULL_VALUE); | |
835 | return; | |
836 | default: | |
837 | math_error("Illegal value for norm"); | |
838 | } | |
839 | } | |
840 | ||
841 | ||
842 | /* | |
843 | * Shift a value left or right by the specified number of bits. | |
844 | * Negative shift value means shift the direction opposite the selected dir. | |
845 | * Right shifts are defined to lose bits off the low end of the number. | |
846 | * Result is placed in the indicated location. | |
847 | */ | |
848 | void | |
849 | shiftvalue(v1, v2, rightshift, vres) | |
850 | VALUE *v1, *v2, *vres; | |
851 | BOOL rightshift; /* TRUE if shift right instead of left */ | |
852 | { | |
853 | COMPLEX *c; | |
854 | long n = 0; | |
855 | VALUE tmp; | |
856 | ||
857 | if (v2->v_type != V_NUM) | |
858 | math_error("Non-real shift value"); | |
859 | if (qisfrac(v2->v_num)) | |
860 | math_error("Non-integral shift value"); | |
861 | if (v1->v_type != V_OBJ) { | |
862 | if (zisbig(v2->v_num->num)) | |
863 | math_error("Very large shift value"); | |
864 | n = qtoi(v2->v_num); | |
865 | } | |
866 | if (rightshift) | |
867 | n = -n; | |
868 | switch (v1->v_type) { | |
869 | case V_NUM: | |
870 | vres->v_num = qshift(v1->v_num, n); | |
871 | vres->v_type = V_NUM; | |
872 | return; | |
873 | case V_COM: | |
874 | c = cshift(v1->v_com, n); | |
875 | if (!cisreal(c)) { | |
876 | vres->v_com = c; | |
877 | vres->v_type = V_COM; | |
878 | return; | |
879 | } | |
880 | vres->v_num = qlink(c->real); | |
881 | vres->v_type = V_NUM; | |
882 | comfree(c); | |
883 | return; | |
884 | case V_MAT: | |
885 | vres->v_mat = matshift(v1->v_mat, n); | |
886 | vres->v_type = V_MAT; | |
887 | return; | |
888 | case V_OBJ: | |
889 | if (!rightshift) { | |
890 | *vres = objcall(OBJ_SHIFT, v1, v2, NULL_VALUE); | |
891 | return; | |
892 | } | |
893 | tmp.v_num = qneg(v2->v_num); | |
894 | tmp.v_type = V_NUM; | |
895 | *vres = objcall(OBJ_SHIFT, v1, &tmp, NULL_VALUE); | |
896 | qfree(tmp.v_num); | |
897 | return; | |
898 | default: | |
899 | math_error("Bad value for shifting"); | |
900 | } | |
901 | } | |
902 | ||
903 | ||
904 | /* | |
905 | * Scale a value by a power of two. | |
906 | * Result is placed in the indicated location. | |
907 | */ | |
908 | void | |
909 | scalevalue(v1, v2, vres) | |
910 | VALUE *v1, *v2, *vres; | |
911 | { | |
912 | long n = 0; | |
913 | ||
914 | if (v2->v_type != V_NUM) | |
915 | math_error("Non-real scaling factor"); | |
916 | if (qisfrac(v2->v_num)) | |
917 | math_error("Non-integral scaling factor"); | |
918 | if (v1->v_type != V_OBJ) { | |
919 | if (zisbig(v2->v_num->num)) | |
920 | math_error("Very large scaling factor"); | |
921 | n = qtoi(v2->v_num); | |
922 | } | |
923 | switch (v1->v_type) { | |
924 | case V_NUM: | |
925 | vres->v_num = qscale(v1->v_num, n); | |
926 | vres->v_type = V_NUM; | |
927 | return; | |
928 | case V_COM: | |
929 | vres->v_com = cscale(v1->v_com, n); | |
930 | vres->v_type = V_NUM; | |
931 | return; | |
932 | case V_MAT: | |
933 | vres->v_mat = matscale(v1->v_mat, n); | |
934 | vres->v_type = V_MAT; | |
935 | return; | |
936 | case V_OBJ: | |
937 | *vres = objcall(OBJ_SCALE, v1, v2, NULL_VALUE); | |
938 | return; | |
939 | default: | |
940 | math_error("Bad value for scaling"); | |
941 | } | |
942 | } | |
943 | ||
944 | ||
945 | /* | |
946 | * Raise a value to an integral power. | |
947 | * Result is placed in the indicated location. | |
948 | */ | |
949 | void | |
950 | powivalue(v1, v2, vres) | |
951 | VALUE *v1, *v2, *vres; | |
952 | { | |
953 | NUMBER *q; | |
954 | COMPLEX *c; | |
955 | ||
956 | vres->v_type = V_NULL; | |
957 | if (v2->v_type != V_NUM) | |
958 | math_error("Raising value to non-real power"); | |
959 | q = v2->v_num; | |
960 | if (qisfrac(q)) | |
961 | math_error("Raising value to non-integral power"); | |
962 | switch (v1->v_type) { | |
963 | case V_NUM: | |
964 | vres->v_num = qpowi(v1->v_num, q); | |
965 | vres->v_type = V_NUM; | |
966 | return; | |
967 | case V_COM: | |
968 | vres->v_com = cpowi(v1->v_com, q); | |
969 | vres->v_type = V_COM; | |
970 | c = vres->v_com; | |
971 | if (!cisreal(c)) | |
972 | return; | |
973 | vres->v_num = qlink(c->real); | |
974 | vres->v_type = V_NUM; | |
975 | comfree(c); | |
976 | return; | |
977 | case V_MAT: | |
978 | vres->v_mat = matpowi(v1->v_mat, q); | |
979 | vres->v_type = V_MAT; | |
980 | return; | |
981 | case V_OBJ: | |
982 | *vres = objcall(OBJ_POW, v1, v2, NULL_VALUE); | |
983 | return; | |
984 | default: | |
985 | math_error("Illegal value for raising to integer power"); | |
986 | } | |
987 | } | |
988 | ||
989 | ||
990 | /* | |
991 | * Raise one value to another value's power, within the specified error. | |
992 | * Result is placed in the indicated location. | |
993 | */ | |
994 | void | |
995 | powervalue(v1, v2, v3, vres) | |
996 | VALUE *v1, *v2, *v3, *vres; | |
997 | { | |
998 | NUMBER *epsilon; | |
999 | COMPLEX *c, ctmp; | |
1000 | ||
1001 | vres->v_type = V_NULL; | |
1002 | if (v3->v_type != V_NUM) | |
1003 | math_error("Non-real epsilon value for power"); | |
1004 | epsilon = v3->v_num; | |
1005 | if (qisneg(epsilon) || qiszero(epsilon)) | |
1006 | math_error("Non-positive epsilon value for power"); | |
1007 | switch (TWOVAL(v1->v_type, v2->v_type)) { | |
1008 | case TWOVAL(V_NUM, V_NUM): | |
1009 | vres->v_num = qpower(v1->v_num, v2->v_num, epsilon); | |
1010 | vres->v_type = V_NUM; | |
1011 | return; | |
1012 | case TWOVAL(V_NUM, V_COM): | |
1013 | ctmp.real = v1->v_num; | |
1014 | ctmp.imag = &_qzero_; | |
1015 | ctmp.links = 1; | |
1016 | vres->v_com = cpower(&ctmp, v2->v_com, epsilon); | |
1017 | break; | |
1018 | case TWOVAL(V_COM, V_NUM): | |
1019 | ctmp.real = v2->v_num; | |
1020 | ctmp.imag = &_qzero_; | |
1021 | ctmp.links = 1; | |
1022 | vres->v_com = cpower(v1->v_com, &ctmp, epsilon); | |
1023 | break; | |
1024 | case TWOVAL(V_COM, V_COM): | |
1025 | vres->v_com = cpower(v1->v_com, v2->v_com, epsilon); | |
1026 | break; | |
1027 | default: | |
1028 | math_error("Illegal value for raising to power"); | |
1029 | } | |
1030 | /* | |
1031 | * Here for any complex result. | |
1032 | */ | |
1033 | vres->v_type = V_COM; | |
1034 | c = vres->v_com; | |
1035 | if (!cisreal(c)) | |
1036 | return; | |
1037 | vres->v_num = qlink(c->real); | |
1038 | vres->v_type = V_NUM; | |
1039 | comfree(c); | |
1040 | } | |
1041 | ||
1042 | ||
1043 | /* | |
1044 | * Divide one arbitrary value by another one. | |
1045 | * Result is placed in the indicated location. | |
1046 | */ | |
1047 | void | |
1048 | divvalue(v1, v2, vres) | |
1049 | VALUE *v1, *v2, *vres; | |
1050 | { | |
1051 | COMPLEX *c; | |
1052 | COMPLEX ctmp; | |
1053 | VALUE tmpval; | |
1054 | ||
1055 | vres->v_type = V_NULL; | |
1056 | switch (TWOVAL(v1->v_type, v2->v_type)) { | |
1057 | case TWOVAL(V_NUM, V_NUM): | |
1058 | vres->v_num = qdiv(v1->v_num, v2->v_num); | |
1059 | vres->v_type = V_NUM; | |
1060 | return; | |
1061 | case TWOVAL(V_COM, V_NUM): | |
1062 | vres->v_com = cdivq(v1->v_com, v2->v_num); | |
1063 | vres->v_type = V_COM; | |
1064 | return; | |
1065 | case TWOVAL(V_NUM, V_COM): | |
1066 | if (qiszero(v1->v_num)) { | |
1067 | vres->v_num = qlink(&_qzero_); | |
1068 | vres->v_type = V_NUM; | |
1069 | return; | |
1070 | } | |
1071 | ctmp.real = v1->v_num; | |
1072 | ctmp.imag = &_qzero_; | |
1073 | ctmp.links = 1; | |
1074 | vres->v_com = cdiv(&ctmp, v2->v_com); | |
1075 | vres->v_type = V_COM; | |
1076 | return; | |
1077 | case TWOVAL(V_COM, V_COM): | |
1078 | vres->v_com = cdiv(v1->v_com, v2->v_com); | |
1079 | vres->v_type = V_COM; | |
1080 | c = vres->v_com; | |
1081 | if (cisreal(c)) { | |
1082 | vres->v_num = qlink(c->real); | |
1083 | vres->v_type = V_NUM; | |
1084 | comfree(c); | |
1085 | } | |
1086 | return; | |
1087 | case TWOVAL(V_MAT, V_NUM): | |
1088 | case TWOVAL(V_MAT, V_COM): | |
1089 | invertvalue(v2, &tmpval); | |
1090 | vres->v_mat = matmulval(v1->v_mat, &tmpval); | |
1091 | vres->v_type = V_MAT; | |
1092 | freevalue(&tmpval); | |
1093 | return; | |
1094 | default: | |
1095 | if ((v1->v_type != V_OBJ) && (v2->v_type != V_OBJ)) | |
1096 | math_error("Non-compatible values for divide"); | |
1097 | *vres = objcall(OBJ_DIV, v1, v2, NULL_VALUE); | |
1098 | return; | |
1099 | } | |
1100 | } | |
1101 | ||
1102 | ||
1103 | /* | |
1104 | * Divide one arbitrary value by another one keeping only the integer part. | |
1105 | * Result is placed in the indicated location. | |
1106 | */ | |
1107 | void | |
1108 | quovalue(v1, v2, vres) | |
1109 | VALUE *v1, *v2, *vres; | |
1110 | { | |
1111 | COMPLEX *c; | |
1112 | ||
1113 | vres->v_type = V_NULL; | |
1114 | switch (TWOVAL(v1->v_type, v2->v_type)) { | |
1115 | case TWOVAL(V_NUM, V_NUM): | |
1116 | vres->v_num = qquo(v1->v_num, v2->v_num); | |
1117 | vres->v_type = V_NUM; | |
1118 | return; | |
1119 | case TWOVAL(V_COM, V_NUM): | |
1120 | vres->v_com = cquoq(v1->v_com, v2->v_num); | |
1121 | vres->v_type = V_COM; | |
1122 | c = vres->v_com; | |
1123 | if (cisreal(c)) { | |
1124 | vres->v_num = qlink(c->real); | |
1125 | vres->v_type = V_NUM; | |
1126 | comfree(c); | |
1127 | } | |
1128 | return; | |
1129 | case TWOVAL(V_MAT, V_NUM): | |
1130 | case TWOVAL(V_MAT, V_COM): | |
1131 | vres->v_mat = matquoval(v1->v_mat, v2); | |
1132 | vres->v_type = V_MAT; | |
1133 | return; | |
1134 | default: | |
1135 | if ((v1->v_type != V_OBJ) && (v2->v_type != V_OBJ)) | |
1136 | math_error("Non-compatible values for quotient"); | |
1137 | *vres = objcall(OBJ_QUO, v1, v2, NULL_VALUE); | |
1138 | return; | |
1139 | } | |
1140 | } | |
1141 | ||
1142 | ||
1143 | /* | |
1144 | * Divide one arbitrary value by another one keeping only the remainder. | |
1145 | * Result is placed in the indicated location. | |
1146 | */ | |
1147 | void | |
1148 | modvalue(v1, v2, vres) | |
1149 | VALUE *v1, *v2, *vres; | |
1150 | { | |
1151 | COMPLEX *c; | |
1152 | ||
1153 | vres->v_type = V_NULL; | |
1154 | switch (TWOVAL(v1->v_type, v2->v_type)) { | |
1155 | case TWOVAL(V_NUM, V_NUM): | |
1156 | vres->v_num = qmod(v1->v_num, v2->v_num); | |
1157 | vres->v_type = V_NUM; | |
1158 | return; | |
1159 | case TWOVAL(V_COM, V_NUM): | |
1160 | vres->v_com = cmodq(v1->v_com, v2->v_num); | |
1161 | vres->v_type = V_COM; | |
1162 | c = vres->v_com; | |
1163 | if (cisreal(c)) { | |
1164 | vres->v_num = qlink(c->real); | |
1165 | vres->v_type = V_NUM; | |
1166 | comfree(c); | |
1167 | } | |
1168 | return; | |
1169 | case TWOVAL(V_MAT, V_NUM): | |
1170 | case TWOVAL(V_MAT, V_COM): | |
1171 | vres->v_mat = matmodval(v1->v_mat, v2); | |
1172 | vres->v_type = V_MAT; | |
1173 | return; | |
1174 | default: | |
1175 | if ((v1->v_type != V_OBJ) && (v2->v_type != V_OBJ)) | |
1176 | math_error("Non-compatible values for mod"); | |
1177 | *vres = objcall(OBJ_MOD, v1, v2, NULL_VALUE); | |
1178 | return; | |
1179 | } | |
1180 | } | |
1181 | ||
1182 | ||
1183 | /* | |
1184 | * Test an arbitrary value to see if it is equal to "zero". | |
1185 | * The definition of zero varies depending on the value type. For example, | |
1186 | * the null string is "zero", and a matrix with zero values is "zero". | |
1187 | * Returns TRUE if value is not equal to zero. | |
1188 | */ | |
1189 | BOOL | |
1190 | testvalue(vp) | |
1191 | VALUE *vp; | |
1192 | { | |
1193 | VALUE val; | |
1194 | ||
1195 | switch (vp->v_type) { | |
1196 | case V_NUM: | |
1197 | return !qiszero(vp->v_num); | |
1198 | case V_COM: | |
1199 | return !ciszero(vp->v_com); | |
1200 | case V_STR: | |
1201 | return (vp->v_str[0] != '\0'); | |
1202 | case V_MAT: | |
1203 | return mattest(vp->v_mat); | |
1204 | case V_LIST: | |
1205 | return (vp->v_list->l_count != 0); | |
1206 | case V_ASSOC: | |
1207 | return (vp->v_assoc->a_count != 0); | |
1208 | case V_FILE: | |
1209 | return validid(vp->v_file); | |
1210 | case V_NULL: | |
1211 | return FALSE; | |
1212 | case V_OBJ: | |
1213 | val = objcall(OBJ_TEST, vp, NULL_VALUE, NULL_VALUE); | |
1214 | return (val.v_int != 0); | |
1215 | default: | |
1216 | return TRUE; | |
1217 | } | |
1218 | } | |
1219 | ||
1220 | ||
1221 | /* | |
1222 | * Compare two values for equality. | |
1223 | * Returns TRUE if the two values differ. | |
1224 | */ | |
1225 | BOOL | |
1226 | comparevalue(v1, v2) | |
1227 | VALUE *v1, *v2; | |
1228 | { | |
1229 | int r = FALSE; | |
1230 | VALUE val; | |
1231 | ||
1232 | if ((v1->v_type == V_OBJ) || (v2->v_type == V_OBJ)) { | |
1233 | val = objcall(OBJ_CMP, v1, v2, NULL_VALUE); | |
1234 | return (val.v_int != 0); | |
1235 | } | |
1236 | if (v1 == v2) | |
1237 | return FALSE; | |
1238 | if (v1->v_type != v2->v_type) | |
1239 | return TRUE; | |
1240 | switch (v1->v_type) { | |
1241 | case V_NUM: | |
1242 | r = qcmp(v1->v_num, v2->v_num); | |
1243 | break; | |
1244 | case V_COM: | |
1245 | r = ccmp(v1->v_com, v2->v_com); | |
1246 | break; | |
1247 | case V_STR: | |
1248 | r = ((v1->v_str != v2->v_str) && | |
1249 | ((v1->v_str[0] - v2->v_str[0]) || | |
1250 | strcmp(v1->v_str, v2->v_str))); | |
1251 | break; | |
1252 | case V_MAT: | |
1253 | r = matcmp(v1->v_mat, v2->v_mat); | |
1254 | break; | |
1255 | case V_LIST: | |
1256 | r = listcmp(v1->v_list, v2->v_list); | |
1257 | break; | |
1258 | case V_ASSOC: | |
1259 | r = assoccmp(v1->v_assoc, v2->v_assoc); | |
1260 | break; | |
1261 | case V_NULL: | |
1262 | break; | |
1263 | case V_FILE: | |
1264 | r = (v1->v_file != v2->v_file); | |
1265 | break; | |
1266 | default: | |
1267 | math_error("Illegal values for comparevalue"); | |
1268 | } | |
1269 | return (r != 0); | |
1270 | } | |
1271 | ||
1272 | ||
1273 | /* | |
1274 | * Compare two values for their relative values. | |
1275 | * Returns minus one if the first value is less than the second one, | |
1276 | * one if the first value is greater than the second one, and | |
1277 | * zero if they are equal. | |
1278 | */ | |
1279 | FLAG | |
1280 | relvalue(v1, v2) | |
1281 | VALUE *v1, *v2; | |
1282 | { | |
1283 | int r = 0; | |
1284 | VALUE val; | |
1285 | ||
1286 | if ((v1->v_type == V_OBJ) || (v2->v_type == V_OBJ)) { | |
1287 | val = objcall(OBJ_REL, v1, v2, NULL_VALUE); | |
1288 | return val.v_int; | |
1289 | } | |
1290 | if (v1 == v2) | |
1291 | return 0; | |
1292 | if (v1->v_type != v2->v_type) | |
1293 | math_error("Relative comparison of differing types"); | |
1294 | switch (v1->v_type) { | |
1295 | case V_NUM: | |
1296 | r = qrel(v1->v_num, v2->v_num); | |
1297 | break; | |
1298 | case V_STR: | |
1299 | r = strcmp(v1->v_str, v2->v_str); | |
1300 | break; | |
1301 | case V_NULL: | |
1302 | break; | |
1303 | default: | |
1304 | math_error("Illegal value for relative comparison"); | |
1305 | } | |
1306 | if (r < 0) | |
1307 | return -1; | |
1308 | return (r != 0); | |
1309 | } | |
1310 | ||
1311 | ||
1312 | /* | |
1313 | * Calculate a hash value for a value. | |
1314 | * The hash does not have to be a perfect one, it is only used for | |
1315 | * making associations faster. | |
1316 | */ | |
1317 | HASH | |
1318 | hashvalue(vp) | |
1319 | VALUE *vp; | |
1320 | { | |
1321 | switch (vp->v_type) { | |
1322 | case V_INT: | |
1323 | return ((long) vp->v_int); | |
1324 | case V_NUM: | |
1325 | return qhash(vp->v_num); | |
1326 | case V_COM: | |
1327 | return chash(vp->v_com); | |
1328 | case V_STR: | |
1329 | return hashstr(vp->v_str); | |
1330 | case V_NULL: | |
1331 | return 0; | |
1332 | case V_OBJ: | |
1333 | return objhash(vp->v_obj); | |
1334 | case V_LIST: | |
1335 | return listhash(vp->v_list); | |
1336 | case V_ASSOC: | |
1337 | return assochash(vp->v_assoc); | |
1338 | case V_MAT: | |
1339 | return mathash(vp->v_mat); | |
1340 | case V_FILE: | |
1341 | return ((long) vp->v_file); | |
1342 | default: | |
1343 | math_error("Hashing unknown value"); | |
1344 | } | |
1345 | return 0; | |
1346 | } | |
1347 | ||
1348 | ||
1349 | /* | |
1350 | * Print the value of a descriptor in one of several formats. | |
1351 | * If flags contains PRINT_SHORT, then elements of arrays and lists | |
1352 | * will not be printed. If flags contains PRINT_UNAMBIG, then quotes | |
1353 | * are placed around strings and the null value is explicitly printed. | |
1354 | */ | |
1355 | void | |
1356 | printvalue(vp, flags) | |
1357 | VALUE *vp; | |
1358 | int flags; | |
1359 | { | |
1360 | switch (vp->v_type) { | |
1361 | case V_NUM: | |
1362 | qprintnum(vp->v_num, MODE_DEFAULT); | |
1363 | break; | |
1364 | case V_COM: | |
1365 | comprint(vp->v_com); | |
1366 | break; | |
1367 | case V_STR: | |
1368 | if (flags & PRINT_UNAMBIG) | |
1369 | math_chr('\"'); | |
1370 | math_str(vp->v_str); | |
1371 | if (flags & PRINT_UNAMBIG) | |
1372 | math_chr('\"'); | |
1373 | break; | |
1374 | case V_NULL: | |
1375 | if (flags & PRINT_UNAMBIG) | |
1376 | math_str("NULL"); | |
1377 | break; | |
1378 | case V_OBJ: | |
1379 | (void) objcall(OBJ_PRINT, vp, NULL_VALUE, NULL_VALUE); | |
1380 | break; | |
1381 | case V_LIST: | |
1382 | listprint(vp->v_list, | |
1383 | ((flags & PRINT_SHORT) ? 0L : maxprint)); | |
1384 | break; | |
1385 | case V_ASSOC: | |
1386 | assocprint(vp->v_assoc, | |
1387 | ((flags & PRINT_SHORT) ? 0L : maxprint)); | |
1388 | break; | |
1389 | case V_MAT: | |
1390 | matprint(vp->v_mat, | |
1391 | ((flags & PRINT_SHORT) ? 0L : maxprint)); | |
1392 | break; | |
1393 | case V_FILE: | |
1394 | printid(vp->v_file, flags); | |
1395 | break; | |
1396 | default: | |
1397 | math_error("Printing unknown value"); | |
1398 | } | |
1399 | } | |
1400 | ||
1401 | /* END CODE */ |