* Un-deprecated the *FIXABLE macros.
[bpt/guile.git] / libguile / numbers.c
CommitLineData
f81e080b
DH
1/* Copyright (C) 1995,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
2 *
0f2d19dd
JB
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd
JB
45\f
46
47#include <stdio.h>
48#include <math.h>
a0599745 49#include "libguile/_scm.h"
a0599745
MD
50#include "libguile/feature.h"
51#include "libguile/ports.h"
52#include "libguile/root.h"
53#include "libguile/smob.h"
54#include "libguile/strings.h"
55#include "libguile/vectors.h"
56
57#include "libguile/validate.h"
58#include "libguile/numbers.h"
f4c627b3 59
0f2d19dd 60\f
f4c627b3
DH
61
62static SCM scm_divbigbig (SCM_BIGDIG *x, scm_sizet nx, SCM_BIGDIG *y, scm_sizet ny, int sgn, int modes);
63static SCM scm_divbigint (SCM x, long z, int sgn, int mode);
64
65
0f2d19dd
JB
66#define DIGITS '0':case '1':case '2':case '3':case '4':\
67 case '5':case '6':case '7':case '8':case '9'
68
69
09fb7599
DH
70#define SCM_SWAP(x,y) do { SCM __t = x; x = y; y = __t; } while (0)
71
72
3a9809df 73#if (SCM_DEBUG_DEPRECATED == 1) /* not defined in header yet? */
3a9809df
DH
74
75/* SCM_FLOBUFLEN is the maximum number of characters neccessary for the
76 * printed or scm_string representation of an inexact number.
77 */
78#define SCM_FLOBUFLEN (10+2*(sizeof(double)/sizeof(char)*SCM_CHAR_BIT*3+9)/10)
894a712b
DH
79
80#endif /* SCM_DEBUG_DEPRECATED == 1 */
3a9809df
DH
81
82
0f2d19dd 83/* IS_INF tests its floating point number for infiniteness
5986c47d 84 Dirk:FIXME:: This test does not work if x == 0
0f2d19dd
JB
85 */
86#ifndef IS_INF
7235ee58 87#define IS_INF(x) ((x) == (x) / 2)
0f2d19dd
JB
88#endif
89
5986c47d 90
e6f3ef58 91/* Return true if X is not infinite and is not a NaN
5986c47d 92 Dirk:FIXME:: Since IS_INF is broken, this test does not work if x == 0
e6f3ef58
MD
93 */
94#ifndef isfinite
95#define isfinite(x) (!IS_INF (x) && (x) == (x))
96#endif
97
0f2d19dd
JB
98\f
99
f872b822 100
a1ec6916 101SCM_DEFINE (scm_exact_p, "exact?", 1, 0, 0,
1bbd0b84 102 (SCM x),
4219f20d 103 "Return #t if X is an exact number, #f otherwise.")
1bbd0b84 104#define FUNC_NAME s_scm_exact_p
0f2d19dd 105{
4219f20d 106 if (SCM_INUMP (x)) {
f872b822 107 return SCM_BOOL_T;
4219f20d 108 } else if (SCM_BIGP (x)) {
f872b822 109 return SCM_BOOL_T;
4219f20d
DH
110 } else {
111 return SCM_BOOL_F;
112 }
0f2d19dd 113}
1bbd0b84 114#undef FUNC_NAME
0f2d19dd 115
4219f20d 116
a1ec6916 117SCM_DEFINE (scm_odd_p, "odd?", 1, 0, 0,
1bbd0b84 118 (SCM n),
4219f20d 119 "Return #t if N is an odd number, #f otherwise.")
1bbd0b84 120#define FUNC_NAME s_scm_odd_p
0f2d19dd 121{
4219f20d
DH
122 if (SCM_INUMP (n)) {
123 return SCM_BOOL ((4 & SCM_UNPACK (n)) != 0);
4219f20d
DH
124 } else if (SCM_BIGP (n)) {
125 return SCM_BOOL ((1 & SCM_BDIGITS (n) [0]) != 0);
4219f20d 126 } else {
a1a33b0f 127 SCM_WRONG_TYPE_ARG (1, n);
4219f20d 128 }
0f2d19dd 129}
1bbd0b84 130#undef FUNC_NAME
0f2d19dd 131
4219f20d 132
a1ec6916 133SCM_DEFINE (scm_even_p, "even?", 1, 0, 0,
1bbd0b84 134 (SCM n),
4219f20d 135 "Return #t if N is an even number, #f otherwise.")
1bbd0b84 136#define FUNC_NAME s_scm_even_p
0f2d19dd 137{
4219f20d
DH
138 if (SCM_INUMP (n)) {
139 return SCM_BOOL ((4 & SCM_UNPACK (n)) == 0);
4219f20d
DH
140 } else if (SCM_BIGP (n)) {
141 return SCM_BOOL ((1 & SCM_BDIGITS (n) [0]) == 0);
4219f20d 142 } else {
a1a33b0f 143 SCM_WRONG_TYPE_ARG (1, n);
4219f20d 144 }
0f2d19dd 145}
1bbd0b84 146#undef FUNC_NAME
0f2d19dd 147
4219f20d 148
9de33deb 149SCM_GPROC (s_abs, "abs", 1, 0, 0, scm_abs, g_abs);
1cc91f1b 150
0f2d19dd 151SCM
6e8d25a6 152scm_abs (SCM x)
0f2d19dd 153{
4219f20d
DH
154 if (SCM_INUMP (x)) {
155 long int xx = SCM_INUM (x);
156 if (xx >= 0) {
157 return x;
158 } else if (SCM_POSFIXABLE (-xx)) {
159 return SCM_MAKINUM (-xx);
160 } else {
0f2d19dd 161#ifdef SCM_BIGDIG
4219f20d 162 return scm_long2big (-xx);
0f2d19dd 163#else
4219f20d 164 scm_num_overflow (s_abs);
0f2d19dd 165#endif
4219f20d 166 }
4219f20d
DH
167 } else if (SCM_BIGP (x)) {
168 if (!SCM_BIGSIGN (x)) {
169 return x;
170 } else {
171 return scm_copybig (x, 0);
172 }
5986c47d
DH
173 } else if (SCM_REALP (x)) {
174 return scm_make_real (fabs (SCM_REAL_VALUE (x)));
4219f20d
DH
175 } else {
176 SCM_WTA_DISPATCH_1 (g_abs, x, 1, s_abs);
177 }
0f2d19dd
JB
178}
179
4219f20d 180
9de33deb 181SCM_GPROC (s_quotient, "quotient", 2, 0, 0, scm_quotient, g_quotient);
1cc91f1b 182
0f2d19dd 183SCM
6e8d25a6 184scm_quotient (SCM x, SCM y)
0f2d19dd 185{
828865c3
DH
186 if (SCM_INUMP (x)) {
187 long xx = SCM_INUM (x);
188 if (SCM_INUMP (y)) {
189 long yy = SCM_INUM (y);
190 if (yy == 0) {
191 scm_num_overflow (s_quotient);
192 } else {
193 long z = xx / yy;
4219f20d
DH
194 if (SCM_FIXABLE (z)) {
195 return SCM_MAKINUM (z);
196 } else {
828865c3
DH
197#ifdef SCM_BIGDIG
198 return scm_long2big (z);
199#else
200 scm_num_overflow (s_quotient);
201#endif
828865c3
DH
202 }
203 }
4219f20d
DH
204 } else if (SCM_BIGP (y)) {
205 return SCM_INUM0;
4219f20d
DH
206 } else {
207 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG2, s_quotient);
828865c3 208 }
4219f20d
DH
209 } else if (SCM_BIGP (x)) {
210 if (SCM_INUMP (y)) {
828865c3
DH
211 long yy = SCM_INUM (y);
212 if (yy == 0) {
213 scm_num_overflow (s_quotient);
214 } else if (yy == 1) {
f872b822 215 return x;
828865c3
DH
216 } else {
217 long z = yy < 0 ? -yy : yy;
218
219 if (z < SCM_BIGRAD) {
220 SCM sw = scm_copybig (x, SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0));
c209c88e
GB
221 scm_divbigdig (SCM_BDIGITS (sw), SCM_NUMDIGS (sw), (SCM_BIGDIG) z);
222 return scm_normbig (sw);
828865c3 223 } else {
0f2d19dd 224#ifndef SCM_DIGSTOOBIG
828865c3
DH
225 long w = scm_pseudolong (z);
226 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
227 (SCM_BIGDIG *) & w, SCM_DIGSPERLONG,
228 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 2);
0f2d19dd 229#else
828865c3
DH
230 SCM_BIGDIG zdigs[SCM_DIGSPERLONG];
231 scm_longdigs (z, zdigs);
232 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
233 zdigs, SCM_DIGSPERLONG,
234 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 2);
f872b822 235#endif
f872b822 236 }
828865c3 237 }
4219f20d
DH
238 } else if (SCM_BIGP (y)) {
239 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
240 SCM_BDIGITS (y), SCM_NUMDIGS (y),
241 SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y), 2);
242 } else {
243 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG2, s_quotient);
f872b822 244 }
4219f20d 245 } else {
89a7e495 246 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG1, s_quotient);
0f2d19dd 247 }
0f2d19dd
JB
248}
249
4219f20d 250
9de33deb 251SCM_GPROC (s_remainder, "remainder", 2, 0, 0, scm_remainder, g_remainder);
1cc91f1b 252
0f2d19dd 253SCM
6e8d25a6 254scm_remainder (SCM x, SCM y)
0f2d19dd 255{
89a7e495
DH
256 if (SCM_INUMP (x)) {
257 if (SCM_INUMP (y)) {
258 long yy = SCM_INUM (y);
259 if (yy == 0) {
260 scm_num_overflow (s_remainder);
261 } else {
89a7e495 262 long z = SCM_INUM (x) % yy;
89a7e495
DH
263 return SCM_MAKINUM (z);
264 }
89a7e495 265 } else if (SCM_BIGP (y)) {
f872b822 266 return x;
89a7e495
DH
267 } else {
268 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG2, s_remainder);
269 }
89a7e495
DH
270 } else if (SCM_BIGP (x)) {
271 if (SCM_INUMP (y)) {
272 long yy = SCM_INUM (y);
273 if (yy == 0) {
274 scm_num_overflow (s_remainder);
275 } else {
276 return scm_divbigint (x, yy, SCM_BIGSIGN (x), 0);
277 }
278 } else if (SCM_BIGP (y)) {
279 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
280 SCM_BDIGITS (y), SCM_NUMDIGS (y),
281 SCM_BIGSIGN (x), 0);
282 } else {
283 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG2, s_remainder);
f872b822 284 }
89a7e495
DH
285 } else {
286 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG1, s_remainder);
287 }
0f2d19dd
JB
288}
289
89a7e495 290
9de33deb 291SCM_GPROC (s_modulo, "modulo", 2, 0, 0, scm_modulo, g_modulo);
1cc91f1b 292
0f2d19dd 293SCM
6e8d25a6 294scm_modulo (SCM x, SCM y)
0f2d19dd 295{
828865c3
DH
296 if (SCM_INUMP (x)) {
297 long xx = SCM_INUM (x);
298 if (SCM_INUMP (y)) {
299 long yy = SCM_INUM (y);
300 if (yy == 0) {
301 scm_num_overflow (s_modulo);
302 } else {
828865c3 303 long z = xx % yy;
828865c3
DH
304 return SCM_MAKINUM (((yy < 0) ? (z > 0) : (z < 0)) ? z + yy : z);
305 }
09fb7599
DH
306 } else if (SCM_BIGP (y)) {
307 return (SCM_BIGSIGN (y) ? (xx > 0) : (xx < 0)) ? scm_sum (x, y) : x;
09fb7599
DH
308 } else {
309 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG2, s_modulo);
f872b822 310 }
09fb7599
DH
311 } else if (SCM_BIGP (x)) {
312 if (SCM_INUMP (y)) {
828865c3
DH
313 long yy = SCM_INUM (y);
314 if (yy == 0) {
315 scm_num_overflow (s_modulo);
316 } else {
317 return scm_divbigint (x, yy, yy < 0,
318 (SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0)) ? 1 : 0);
319 }
09fb7599
DH
320 } else if (SCM_BIGP (y)) {
321 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
322 SCM_BDIGITS (y), SCM_NUMDIGS (y),
323 SCM_BIGSIGN (y),
324 (SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y)) ? 1 : 0);
325 } else {
326 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG2, s_modulo);
828865c3 327 }
09fb7599
DH
328 } else {
329 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG1, s_modulo);
828865c3 330 }
0f2d19dd
JB
331}
332
09fb7599 333
9de33deb 334SCM_GPROC1 (s_gcd, "gcd", scm_tc7_asubr, scm_gcd, g_gcd);
1cc91f1b 335
0f2d19dd 336SCM
6e8d25a6 337scm_gcd (SCM x, SCM y)
0f2d19dd 338{
09fb7599
DH
339 if (SCM_UNBNDP (y)) {
340 if (SCM_UNBNDP (x)) {
341 return SCM_INUM0;
342 } else {
343 return x;
344 }
345 }
f8de44c1 346
0f2d19dd 347 tailrec:
09fb7599
DH
348 if (SCM_INUMP (x)) {
349 if (SCM_INUMP (y)) {
350 long xx = SCM_INUM (x);
351 long yy = SCM_INUM (y);
352 long u = xx < 0 ? -xx : xx;
353 long v = yy < 0 ? -yy : yy;
354 long result;
355
356 if (xx == 0) {
357 result = v;
358 } else if (yy == 0) {
359 result = u;
360 } else {
361 int k = 1;
362 long t;
363
364 /* Determine a common factor 2^k */
365 while (!(1 & (u | v))) {
366 k <<= 1;
367 u >>= 1;
368 v >>= 1;
f872b822 369 }
09fb7599
DH
370
371 /* Now, any factor 2^n can be eliminated */
372 if (u & 1) {
373 t = -v;
374 } else {
375 t = u;
376 b3:
377 t = SCM_SRS (t, 1);
378 }
379 if (!(1 & t))
380 goto b3;
381 if (t > 0)
382 u = t;
383 else
384 v = -t;
385 t = u - v;
386 if (t != 0)
387 goto b3;
388
389 result = u * k;
390 }
391 if (SCM_POSFIXABLE (result)) {
392 return SCM_MAKINUM (result);
393 } else {
394#ifdef SCM_BIGDIG
395 return scm_long2big (result);
f872b822 396#else
09fb7599
DH
397 scm_num_overflow (s_gcd);
398#endif
399 }
09fb7599
DH
400 } else if (SCM_BIGP (y)) {
401 SCM_SWAP (x, y);
402 goto big_gcd;
09fb7599
DH
403 } else {
404 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
f872b822 405 }
09fb7599
DH
406 } else if (SCM_BIGP (x)) {
407 big_gcd:
408 if (SCM_BIGSIGN (x))
409 x = scm_copybig (x, 0);
410 newy:
411 if (SCM_INUMP (y)) {
412 if (SCM_EQ_P (y, SCM_INUM0)) {
413 return x;
414 } else {
415 goto swaprec;
416 }
417 } else if (SCM_BIGP (y)) {
418 if (SCM_BIGSIGN (y))
419 y = scm_copybig (y, 0);
420 switch (scm_bigcomp (x, y))
421 {
422 case -1: /* x > y */
423 swaprec:
424 {
425 SCM t = scm_remainder (x, y);
426 x = y;
427 y = t;
428 }
429 goto tailrec;
430 case 1: /* x < y */
431 y = scm_remainder (y, x);
432 goto newy;
433 default: /* x == y */
434 return x;
435 }
436 /* instead of the switch, we could just
437 return scm_gcd (y, scm_modulo (x, y)); */
438 } else {
439 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
440 }
09fb7599
DH
441 } else {
442 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG1, s_gcd);
443 }
0f2d19dd
JB
444}
445
09fb7599 446
9de33deb 447SCM_GPROC1 (s_lcm, "lcm", scm_tc7_asubr, scm_lcm, g_lcm);
1cc91f1b 448
0f2d19dd 449SCM
6e8d25a6 450scm_lcm (SCM n1, SCM n2)
0f2d19dd 451{
09fb7599
DH
452 if (SCM_UNBNDP (n2)) {
453 if (SCM_UNBNDP (n1)) {
454 return SCM_MAKINUM (1L);
455 } else {
456 n2 = SCM_MAKINUM (1L);
457 }
458 };
459
02a3305a 460#ifndef SCM_BIGDIG
09fb7599
DH
461 SCM_GASSERT2 (SCM_INUMP (n1), g_lcm, n1, n2, SCM_ARG1, s_lcm);
462 SCM_GASSERT2 (SCM_INUMP (n2), g_lcm, n1, n2, SCM_ARGn, s_lcm);
9de33deb 463#else
09fb7599 464 SCM_GASSERT2 (SCM_INUMP (n1) || SCM_BIGP (n1),
9de33deb 465 g_lcm, n1, n2, SCM_ARG1, s_lcm);
09fb7599 466 SCM_GASSERT2 (SCM_INUMP (n2) || SCM_BIGP (n2),
9de33deb
MD
467 g_lcm, n1, n2, SCM_ARGn, s_lcm);
468#endif
09fb7599
DH
469
470 {
471 SCM d = scm_gcd (n1, n2);
472 if (SCM_EQ_P (d, SCM_INUM0)) {
473 return d;
474 } else {
475 return scm_abs (scm_product (n1, scm_quotient (n2, d)));
f872b822 476 }
09fb7599 477 }
0f2d19dd
JB
478}
479
09fb7599 480
0f2d19dd 481#ifndef scm_long2num
c1bfcf60
GB
482#define SCM_LOGOP_RETURN(x) scm_ulong2num(x)
483#else
484#define SCM_LOGOP_RETURN(x) SCM_MAKINUM(x)
485#endif
486
8a525303
GB
487
488/* Emulating 2's complement bignums with sign magnitude arithmetic:
489
490 Logand:
491 X Y Result Method:
492 (len)
493 + + + x (map digit:logand X Y)
494 + - + x (map digit:logand X (lognot (+ -1 Y)))
495 - + + y (map digit:logand (lognot (+ -1 X)) Y)
496 - - - (+ 1 (map digit:logior (+ -1 X) (+ -1 Y)))
497
498 Logior:
499 X Y Result Method:
500
501 + + + (map digit:logior X Y)
502 + - - y (+ 1 (map digit:logand (lognot X) (+ -1 Y)))
503 - + - x (+ 1 (map digit:logand (+ -1 X) (lognot Y)))
504 - - - x (+ 1 (map digit:logand (+ -1 X) (+ -1 Y)))
505
506 Logxor:
507 X Y Result Method:
508
509 + + + (map digit:logxor X Y)
510 + - - (+ 1 (map digit:logxor X (+ -1 Y)))
511 - + - (+ 1 (map digit:logxor (+ -1 X) Y))
512 - - + (map digit:logxor (+ -1 X) (+ -1 Y))
513
514 Logtest:
515 X Y Result
516
517 + + (any digit:logand X Y)
518 + - (any digit:logand X (lognot (+ -1 Y)))
519 - + (any digit:logand (lognot (+ -1 X)) Y)
520 - - #t
521
522*/
523
524#ifdef SCM_BIGDIG
525
526SCM scm_copy_big_dec(SCM b, int sign);
527SCM scm_copy_smaller(SCM_BIGDIG *x, scm_sizet nx, int zsgn);
528SCM scm_big_ior(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy);
529SCM scm_big_xor(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy);
530SCM scm_big_and(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy, int zsgn);
531SCM scm_big_test(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy);
532
533SCM scm_copy_big_dec(SCM b, int sign)
534{
535 long num = -1;
536 scm_sizet nx = SCM_NUMDIGS(b);
537 scm_sizet i = 0;
538 SCM ans = scm_mkbig(nx, sign);
539 SCM_BIGDIG *src = SCM_BDIGITS(b), *dst = SCM_BDIGITS(ans);
540 if SCM_BIGSIGN(b) do {
541 num += src[i];
542 if (num < 0) {dst[i] = num + SCM_BIGRAD; num = -1;}
543 else {dst[i] = SCM_BIGLO(num); num = 0;}
544 } while (++i < nx);
545 else
546 while (nx--) dst[nx] = src[nx];
547 return ans;
548}
549
550SCM scm_copy_smaller(SCM_BIGDIG *x, scm_sizet nx, int zsgn)
551{
552 long num = -1;
553 scm_sizet i = 0;
554 SCM z = scm_mkbig(nx, zsgn);
555 SCM_BIGDIG *zds = SCM_BDIGITS(z);
556 if (zsgn) do {
557 num += x[i];
558 if (num < 0) {zds[i] = num + SCM_BIGRAD; num = -1;}
559 else {zds[i] = SCM_BIGLO(num); num = 0;}
560 } while (++i < nx);
561 else do zds[i] = x[i]; while (++i < nx);
562 return z;
563}
564
565SCM scm_big_ior(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy)
566/* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60 567/* Assumes xsgn equals either 0 or SCM_BIGSIGNFLAG */
8a525303
GB
568{
569 long num = -1;
570 scm_sizet i = 0, ny = SCM_NUMDIGS(bigy);
f3ae5d60 571 SCM z = scm_copy_big_dec (bigy, xsgn & SCM_BIGSIGN (bigy));
8a525303
GB
572 SCM_BIGDIG *zds = SCM_BDIGITS(z);
573 if (xsgn) {
574 do {
575 num += x[i];
576 if (num < 0) {zds[i] |= num + SCM_BIGRAD; num = -1;}
577 else {zds[i] |= SCM_BIGLO(num); num = 0;}
578 } while (++i < nx);
579 /* ========= Need to increment zds now =========== */
580 i = 0; num = 1;
581 while (i < ny) {
582 num += zds[i];
583 zds[i++] = SCM_BIGLO(num);
584 num = SCM_BIGDN(num);
585 if (!num) return z;
586 }
587 scm_adjbig(z, 1 + ny); /* OOPS, overflowed into next digit. */
588 SCM_BDIGITS(z)[ny] = 1;
589 return z;
590 }
591 else do zds[i] = zds[i] | x[i]; while (++i < nx);
592 return z;
593}
594
595SCM scm_big_xor(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy)
596/* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60 597/* Assumes xsgn equals either 0 or SCM_BIGSIGNFLAG */
8a525303
GB
598{
599 long num = -1;
600 scm_sizet i = 0, ny = SCM_NUMDIGS(bigy);
601 SCM z = scm_copy_big_dec(bigy, xsgn ^ SCM_BIGSIGN(bigy));
602 SCM_BIGDIG *zds = SCM_BDIGITS(z);
603 if (xsgn) do {
604 num += x[i];
605 if (num < 0) {zds[i] ^= num + SCM_BIGRAD; num = -1;}
606 else {zds[i] ^= SCM_BIGLO(num); num = 0;}
607 } while (++i < nx);
608 else do {
609 zds[i] = zds[i] ^ x[i];
610 } while (++i < nx);
611
612 if (xsgn ^ SCM_BIGSIGN(bigy)) {
613 /* ========= Need to increment zds now =========== */
614 i = 0; num = 1;
615 while (i < ny) {
616 num += zds[i];
617 zds[i++] = SCM_BIGLO(num);
618 num = SCM_BIGDN(num);
619 if (!num) return scm_normbig(z);
620 }
621 }
622 return scm_normbig(z);
623}
624
625SCM scm_big_and(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy, int zsgn)
626/* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60
MD
627/* Assumes xsgn equals either 0 or SCM_BIGSIGNFLAG */
628/* return sign equals either 0 or SCM_BIGSIGNFLAG */
8a525303
GB
629{
630 long num = -1;
631 scm_sizet i = 0;
632 SCM z;
633 SCM_BIGDIG *zds;
634 if (xsgn==zsgn) {
635 z = scm_copy_smaller(x, nx, zsgn);
636 x = SCM_BDIGITS(bigy);
637 xsgn = SCM_BIGSIGN(bigy);
638 }
639 else z = scm_copy_big_dec(bigy, zsgn);
640 zds = SCM_BDIGITS(z);
641
642 if (zsgn) {
643 if (xsgn) do {
644 num += x[i];
645 if (num < 0) {zds[i] &= num + SCM_BIGRAD; num = -1;}
646 else {zds[i] &= SCM_BIGLO(num); num = 0;}
647 } while (++i < nx);
648 else do zds[i] = zds[i] & ~x[i]; while (++i < nx);
649 /* ========= need to increment zds now =========== */
650 i = 0; num = 1;
651 while (i < nx) {
652 num += zds[i];
653 zds[i++] = SCM_BIGLO(num);
654 num = SCM_BIGDN(num);
655 if (!num) return scm_normbig(z);
656 }
657 }
658 else if (xsgn) do {
659 num += x[i];
660 if (num < 0) {zds[i] &= num + SCM_BIGRAD; num = -1;}
661 else {zds[i] &= ~SCM_BIGLO(num); num = 0;}
662 } while (++i < nx);
663 else do zds[i] = zds[i] & x[i]; while (++i < nx);
664 return scm_normbig(z);
665}
666
667SCM scm_big_test(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy)
668/* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60 669/* Assumes xsgn equals either 0 or SCM_BIGSIGNFLAG */
8a525303
GB
670{
671 SCM_BIGDIG *y;
672 scm_sizet i = 0;
673 long num = -1;
674 if (SCM_BIGSIGN(bigy) & xsgn) return SCM_BOOL_T;
675 if (SCM_NUMDIGS(bigy) != nx && xsgn) return SCM_BOOL_T;
676 y = SCM_BDIGITS(bigy);
677 if (xsgn)
678 do {
679 num += x[i];
680 if (num < 0) {
681 if (y[i] & ~(num + SCM_BIGRAD)) return SCM_BOOL_T;
682 num = -1;
683 }
684 else {
685 if (y[i] & ~SCM_BIGLO(num)) return SCM_BOOL_T;
686 num = 0;
687 }
688 } while (++i < nx);
689 else if SCM_BIGSIGN(bigy)
690 do {
691 num += y[i];
692 if (num < 0) {
693 if (x[i] & ~(num + SCM_BIGRAD)) return SCM_BOOL_T;
694 num = -1;
695 }
696 else {
697 if (x[i] & ~SCM_BIGLO(num)) return SCM_BOOL_T;
698 num = 0;
699 }
700 } while (++i < nx);
701 else
702 do if (x[i] & y[i]) return SCM_BOOL_T;
703 while (++i < nx);
704 return SCM_BOOL_F;
705}
706
707#endif
708
09fb7599 709
c3ee7520 710SCM_DEFINE1 (scm_logand, "logand", scm_tc7_asubr,
1bbd0b84 711 (SCM n1, SCM n2),
b380b885
MD
712 "Returns the integer which is the bit-wise AND of the two integer\n"
713 "arguments.\n\n"
714 "Example:\n"
715 "@lisp\n"
716 "(number->string (logand #b1100 #b1010) 2)\n"
717 " @result{} \"1000\"")
1bbd0b84 718#define FUNC_NAME s_scm_logand
0f2d19dd 719{
9a00c9fc
DH
720 long int nn1;
721
09fb7599
DH
722 if (SCM_UNBNDP (n2)) {
723 if (SCM_UNBNDP (n1)) {
724 return SCM_MAKINUM (-1);
725 } else if (!SCM_NUMBERP (n1)) {
726 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
8a525303 727#ifndef SCM_RECKLESS
09fb7599 728 } else if (SCM_NUMBERP (n1)) {
d28da049 729 return n1;
09fb7599
DH
730 } else {
731 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
732#else
733 } else {
734 return n1;
735#endif
d28da049 736 }
8a525303 737 }
09fb7599
DH
738
739 if (SCM_INUMP (n1)) {
9a00c9fc 740 nn1 = SCM_INUM (n1);
09fb7599
DH
741 if (SCM_INUMP (n2)) {
742 long nn2 = SCM_INUM (n2);
743 return SCM_MAKINUM (nn1 & nn2);
09fb7599
DH
744 } else if SCM_BIGP (n2) {
745 intbig:
746 {
8a525303 747# ifndef SCM_DIGSTOOBIG
09fb7599
DH
748 long z = scm_pseudolong (nn1);
749 if ((nn1 < 0) && SCM_BIGSIGN (n2)) {
750 return scm_big_ior ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
751 SCM_BIGSIGNFLAG, n2);
752 } else {
753 return scm_big_and ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
754 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, 0);
755 }
8a525303 756# else
09fb7599
DH
757 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
758 scm_longdigs (nn1, zdigs);
759 if ((nn1 < 0) && SCM_BIGSIGN (n2)) {
760 return scm_big_ior (zdigs, SCM_DIGSPERLONG, SCM_BIGSIGNFLAG, n2);
761 } else {
762 return scm_big_and (zdigs, SCM_DIGSPERLONG,
763 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, 0);
764 }
8a525303 765# endif
09fb7599 766 }
09fb7599
DH
767 } else {
768 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
769 }
09fb7599
DH
770 } else if (SCM_BIGP (n1)) {
771 if (SCM_INUMP (n2)) {
772 SCM_SWAP (n1, n2);
9a00c9fc 773 nn1 = SCM_INUM (n1);
09fb7599
DH
774 goto intbig;
775 } else if (SCM_BIGP (n2)) {
776 if (SCM_NUMDIGS (n1) > SCM_NUMDIGS (n2)) {
777 SCM_SWAP (n1, n2);
778 };
779 if ((SCM_BIGSIGN (n1)) && SCM_BIGSIGN (n2)) {
780 return scm_big_ior (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
781 SCM_BIGSIGNFLAG, n2);
782 } else {
783 return scm_big_and (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
784 SCM_BIGSIGN (n1), n2, 0);
785 }
786 } else {
787 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
788 }
09fb7599
DH
789 } else {
790 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
791 }
0f2d19dd 792}
1bbd0b84 793#undef FUNC_NAME
0f2d19dd 794
09fb7599 795
c3ee7520 796SCM_DEFINE1 (scm_logior, "logior", scm_tc7_asubr,
1bbd0b84 797 (SCM n1, SCM n2),
b380b885
MD
798 "Returns the integer which is the bit-wise OR of the two integer\n"
799 "arguments.\n\n"
800 "Example:\n"
801 "@lisp\n"
802 "(number->string (logior #b1100 #b1010) 2)\n"
803 " @result{} \"1110\"\n"
804 "@end lisp")
1bbd0b84 805#define FUNC_NAME s_scm_logior
0f2d19dd 806{
9a00c9fc
DH
807 long int nn1;
808
09fb7599
DH
809 if (SCM_UNBNDP (n2)) {
810 if (SCM_UNBNDP (n1)) {
811 return SCM_INUM0;
8a525303 812#ifndef SCM_RECKLESS
09fb7599 813 } else if (SCM_NUMBERP (n1)) {
d28da049 814 return n1;
09fb7599
DH
815 } else {
816 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
817#else
818 } else {
819 return n1;
820#endif
d28da049 821 }
8a525303 822 }
09fb7599
DH
823
824 if (SCM_INUMP (n1)) {
9a00c9fc 825 nn1 = SCM_INUM (n1);
09fb7599
DH
826 if (SCM_INUMP (n2)) {
827 long nn2 = SCM_INUM (n2);
828 return SCM_MAKINUM (nn1 | nn2);
09fb7599
DH
829 } else if (SCM_BIGP (n2)) {
830 intbig:
831 {
8a525303 832# ifndef SCM_DIGSTOOBIG
09fb7599
DH
833 long z = scm_pseudolong (nn1);
834 if ((!(nn1 < 0)) && !SCM_BIGSIGN (n2)) {
835 return scm_big_ior ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
836 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
837 } else {
838 return scm_big_and ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
839 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, SCM_BIGSIGNFLAG);
840 }
8a525303 841# else
09fb7599
DH
842 BIGDIG zdigs [DIGSPERLONG];
843 scm_longdigs (nn1, zdigs);
844 if ((!(nn1 < 0)) && !SCM_BIGSIGN (n2)) {
845 return scm_big_ior (zdigs, SCM_DIGSPERLONG,
846 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
847 } else {
848 return scm_big_and (zdigs, SCM_DIGSPERLONG,
849 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, SCM_BIGSIGNFLAG);
850 }
8a525303 851# endif
09fb7599 852 }
09fb7599
DH
853 } else {
854 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
855 }
09fb7599
DH
856 } else if (SCM_BIGP (n1)) {
857 if (SCM_INUMP (n2)) {
858 SCM_SWAP (n1, n2);
9a00c9fc 859 nn1 = SCM_INUM (n1);
09fb7599
DH
860 goto intbig;
861 } else if (SCM_BIGP (n2)) {
862 if (SCM_NUMDIGS (n1) > SCM_NUMDIGS (n2)) {
863 SCM_SWAP (n1, n2);
864 };
865 if ((!SCM_BIGSIGN (n1)) && !SCM_BIGSIGN (n2)) {
866 return scm_big_ior (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
867 SCM_BIGSIGN (n1), n2);
868 } else {
869 return scm_big_and (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
870 SCM_BIGSIGN (n1), n2, SCM_BIGSIGNFLAG);
871 }
872 } else {
873 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
874 }
09fb7599
DH
875 } else {
876 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
877 }
0f2d19dd 878}
1bbd0b84 879#undef FUNC_NAME
0f2d19dd 880
09fb7599 881
c3ee7520 882SCM_DEFINE1 (scm_logxor, "logxor", scm_tc7_asubr,
1bbd0b84 883 (SCM n1, SCM n2),
b380b885
MD
884 "Returns the integer which is the bit-wise XOR of the two integer\n"
885 "arguments.\n\n"
886 "Example:\n"
887 "@lisp\n"
888 "(number->string (logxor #b1100 #b1010) 2)\n"
889 " @result{} \"110\"\n"
890 "@end lisp")
1bbd0b84 891#define FUNC_NAME s_scm_logxor
0f2d19dd 892{
9a00c9fc
DH
893 long int nn1;
894
09fb7599
DH
895 if (SCM_UNBNDP (n2)) {
896 if (SCM_UNBNDP (n1)) {
897 return SCM_INUM0;
8a525303 898#ifndef SCM_RECKLESS
09fb7599
DH
899 } else if (SCM_NUMBERP (n1)) {
900 return n1;
901 } else {
902 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
903#else
904 } else {
d28da049 905 return n1;
09fb7599 906#endif
d28da049 907 }
8a525303 908 }
09fb7599
DH
909
910 if (SCM_INUMP (n1)) {
9a00c9fc 911 nn1 = SCM_INUM (n1);
09fb7599
DH
912 if (SCM_INUMP (n2)) {
913 long nn2 = SCM_INUM (n2);
914 return SCM_MAKINUM (nn1 ^ nn2);
09fb7599
DH
915 } else if (SCM_BIGP (n2)) {
916 intbig:
8a525303
GB
917 {
918# ifndef SCM_DIGSTOOBIG
09fb7599
DH
919 long z = scm_pseudolong (nn1);
920 return scm_big_xor ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
921 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
8a525303 922# else
09fb7599
DH
923 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
924 scm_longdigs (nn1, zdigs);
925 return scm_big_xor (zdigs, SCM_DIGSPERLONG,
926 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
8a525303
GB
927# endif
928 }
09fb7599
DH
929 } else {
930 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
931 }
09fb7599
DH
932 } else if (SCM_BIGP (n1)) {
933 if (SCM_INUMP (n2)) {
934 SCM_SWAP (n1, n2);
9a00c9fc 935 nn1 = SCM_INUM (n1);
09fb7599
DH
936 goto intbig;
937 } else if (SCM_BIGP (n2)) {
938 if (SCM_NUMDIGS(n1) > SCM_NUMDIGS(n2)) {
939 SCM_SWAP (n1, n2);
940 }
941 return scm_big_xor (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
942 SCM_BIGSIGN (n1), n2);
943 } else {
944 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
945 }
09fb7599
DH
946 } else {
947 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
948 }
0f2d19dd 949}
1bbd0b84 950#undef FUNC_NAME
0f2d19dd 951
09fb7599 952
a1ec6916 953SCM_DEFINE (scm_logtest, "logtest", 2, 0, 0,
1bbd0b84 954 (SCM n1, SCM n2),
b380b885
MD
955 "@example\n"
956 "(logtest j k) @equiv{} (not (zero? (logand j k)))\n\n"
957 "(logtest #b0100 #b1011) @result{} #f\n"
958 "(logtest #b0100 #b0111) @result{} #t\n"
959 "@end example")
1bbd0b84 960#define FUNC_NAME s_scm_logtest
0f2d19dd 961{
9a00c9fc
DH
962 long int nn1;
963
f8de44c1 964 if (SCM_INUMP (n1)) {
9a00c9fc 965 nn1 = SCM_INUM (n1);
f8de44c1
DH
966 if (SCM_INUMP (n2)) {
967 long nn2 = SCM_INUM (n2);
968 return SCM_BOOL (nn1 & nn2);
f8de44c1
DH
969 } else if (SCM_BIGP (n2)) {
970 intbig:
971 {
8a525303 972# ifndef SCM_DIGSTOOBIG
f8de44c1
DH
973 long z = scm_pseudolong (nn1);
974 return scm_big_test ((SCM_BIGDIG *)&z, SCM_DIGSPERLONG,
975 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
8a525303 976# else
f8de44c1
DH
977 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
978 scm_longdigs (nn1, zdigs);
979 return scm_big_test (zdigs, SCM_DIGSPERLONG,
980 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
8a525303 981# endif
f8de44c1 982 }
f8de44c1
DH
983 } else {
984 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
985 }
f8de44c1
DH
986 } else if (SCM_BIGP (n1)) {
987 if (SCM_INUMP (n2)) {
988 SCM_SWAP (n1, n2);
9a00c9fc 989 nn1 = SCM_INUM (n1);
f8de44c1
DH
990 goto intbig;
991 } else if (SCM_BIGP (n2)) {
992 if (SCM_NUMDIGS (n1) > SCM_NUMDIGS (n2)) {
993 SCM_SWAP (n1, n2);
994 }
995 return scm_big_test (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
996 SCM_BIGSIGN (n1), n2);
997 } else {
998 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
999 }
f8de44c1
DH
1000 } else {
1001 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
1002 }
0f2d19dd 1003}
1bbd0b84 1004#undef FUNC_NAME
0f2d19dd 1005
c1bfcf60 1006
a1ec6916 1007SCM_DEFINE (scm_logbit_p, "logbit?", 2, 0, 0,
2cd04b42 1008 (SCM index, SCM j),
b380b885
MD
1009 "@example\n"
1010 "(logbit? index j) @equiv{} (logtest (integer-expt 2 index) j)\n\n"
1011 "(logbit? 0 #b1101) @result{} #t\n"
1012 "(logbit? 1 #b1101) @result{} #f\n"
1013 "(logbit? 2 #b1101) @result{} #t\n"
1014 "(logbit? 3 #b1101) @result{} #t\n"
1015 "(logbit? 4 #b1101) @result{} #f\n"
1016 "@end example")
1bbd0b84 1017#define FUNC_NAME s_scm_logbit_p
0f2d19dd 1018{
78166ad5
DH
1019 unsigned long int iindex;
1020
1021 SCM_VALIDATE_INUM_MIN (SCM_ARG1, index, 0);
1022 iindex = (unsigned long int) SCM_INUM (index);
1023
1024 if (SCM_INUMP (j)) {
1025 return SCM_BOOL ((1L << iindex) & SCM_INUM (j));
1026 } else if (SCM_BIGP (j)) {
1027 if (SCM_NUMDIGS (j) * SCM_BITSPERDIG < iindex) {
1028 return SCM_BOOL_F;
1029 } else if (SCM_BIGSIGN (j)) {
8a525303
GB
1030 long num = -1;
1031 scm_sizet i = 0;
78166ad5
DH
1032 SCM_BIGDIG * x = SCM_BDIGITS (j);
1033 scm_sizet nx = iindex / SCM_BITSPERDIG;
1034 while (1) {
8a525303 1035 num += x[i];
78166ad5
DH
1036 if (nx == i++) {
1037 return SCM_BOOL (((1L << (iindex % SCM_BITSPERDIG)) & num) == 0);
1038 } else if (num < 0) {
1039 num = -1;
1040 } else {
1041 num = 0;
1042 }
8a525303 1043 }
78166ad5
DH
1044 } else {
1045 return SCM_BOOL (SCM_BDIGITS (j) [iindex / SCM_BITSPERDIG]
1046 & (1L << (iindex % SCM_BITSPERDIG)));
8a525303 1047 }
78166ad5
DH
1048 } else {
1049 SCM_WRONG_TYPE_ARG (SCM_ARG2, j);
8a525303 1050 }
0f2d19dd 1051}
1bbd0b84 1052#undef FUNC_NAME
0f2d19dd 1053
78166ad5 1054
a1ec6916 1055SCM_DEFINE (scm_lognot, "lognot", 1, 0, 0,
1bbd0b84 1056 (SCM n),
b380b885
MD
1057 "Returns the integer which is the 2s-complement of the integer argument.\n\n"
1058 "Example:\n"
1059 "@lisp\n"
1060 "(number->string (lognot #b10000000) 2)\n"
1061 " @result{} \"-10000001\"\n"
1062 "(number->string (lognot #b0) 2)\n"
1063 " @result{} \"-1\"\n"
1064 "@end lisp\n"
1065 "")
1bbd0b84 1066#define FUNC_NAME s_scm_lognot
0f2d19dd 1067{
f872b822 1068 return scm_difference (SCM_MAKINUM (-1L), n);
0f2d19dd 1069}
1bbd0b84 1070#undef FUNC_NAME
0f2d19dd 1071
a1ec6916 1072SCM_DEFINE (scm_integer_expt, "integer-expt", 2, 0, 0,
2cd04b42 1073 (SCM n, SCM k),
b380b885
MD
1074 "Returns @var{n} raised to the non-negative integer exponent @var{k}.\n\n"
1075 "Example:\n"
1076 "@lisp\n"
1077 "(integer-expt 2 5)\n"
1078 " @result{} 32\n"
1079 "(integer-expt -3 3)\n"
1080 " @result{} -27\n"
1081 "@end lisp")
1bbd0b84 1082#define FUNC_NAME s_scm_integer_expt
0f2d19dd 1083{
f872b822 1084 SCM acc = SCM_MAKINUM (1L);
1bbd0b84 1085 int i2;
0f2d19dd 1086#ifdef SCM_BIGDIG
4260a7fc 1087 if (SCM_EQ_P (n, SCM_INUM0) || SCM_EQ_P (n, acc))
2cd04b42 1088 return n;
4260a7fc
DH
1089 else if (SCM_EQ_P (n, SCM_MAKINUM (-1L)))
1090 return SCM_FALSEP (scm_even_p (k)) ? n : acc;
0f2d19dd 1091#endif
2cd04b42 1092 SCM_VALIDATE_ULONG_COPY (2,k,i2);
1bbd0b84 1093 if (i2 < 0)
f872b822 1094 {
1bbd0b84 1095 i2 = -i2;
2cd04b42 1096 n = scm_divide (n, SCM_UNDEFINED);
f872b822
MD
1097 }
1098 while (1)
1099 {
1bbd0b84 1100 if (0 == i2)
f872b822 1101 return acc;
1bbd0b84 1102 if (1 == i2)
2cd04b42 1103 return scm_product (acc, n);
1bbd0b84 1104 if (i2 & 1)
2cd04b42
GB
1105 acc = scm_product (acc, n);
1106 n = scm_product (n, n);
1bbd0b84 1107 i2 >>= 1;
f872b822 1108 }
0f2d19dd 1109}
1bbd0b84 1110#undef FUNC_NAME
0f2d19dd 1111
a1ec6916 1112SCM_DEFINE (scm_ash, "ash", 2, 0, 0,
1bbd0b84 1113 (SCM n, SCM cnt),
3ab9f56e
DH
1114 "The function ash performs an arithmetic shift left by CNT bits\n"
1115 "(or shift right, if CNT is negative). 'Arithmetic' means, that\n"
1116 "the function does not guarantee to keep the bit structure of N,\n"
1117 "but rather guarantees that the result will always be rounded\n"
1118 "towards minus infinity. Therefore, the results of ash and a\n"
1119 "corresponding bitwise shift will differ if N is negative.\n\n"
1120 "Formally, the function returns an integer equivalent to\n"
1121 "@code{(inexact->exact (floor (* N (expt 2 CNT))))}.@refill\n\n"
b380b885
MD
1122 "Example:\n"
1123 "@lisp\n"
1124 "(number->string (ash #b1 3) 2)\n"
a3c8b9fc
MD
1125 " @result{} \"1000\""
1126 "(number->string (ash #b1010 -1) 2)"
1127 " @result{} \"101\""
1128 "@end lisp")
1bbd0b84 1129#define FUNC_NAME s_scm_ash
0f2d19dd 1130{
3ab9f56e
DH
1131 long bits_to_shift;
1132
1133#ifndef SCM_BIGDIG
1134 SCM_VALIDATE_INUM (1, n)
1135#endif
1136 SCM_VALIDATE_INUM (2, cnt);
1137
1138 bits_to_shift = SCM_INUM (cnt);
0f2d19dd 1139#ifdef SCM_BIGDIG
3ab9f56e
DH
1140 if (bits_to_shift < 0) {
1141 /* Shift right by abs(cnt) bits. This is realized as a division by
1142 div:=2^abs(cnt). However, to guarantee the floor rounding, negative
1143 values require some special treatment.
1144 */
1145 SCM div = scm_integer_expt (SCM_MAKINUM (2), SCM_MAKINUM (-bits_to_shift));
1146 if (SCM_FALSEP (scm_negative_p (n)))
1147 return scm_quotient (n, div);
1148 else
1149 return scm_sum (SCM_MAKINUM (-1L),
1150 scm_quotient (scm_sum (SCM_MAKINUM (1L), n), div));
1151 } else
1152 /* Shift left is done by multiplication with 2^CNT */
f872b822 1153 return scm_product (n, scm_integer_expt (SCM_MAKINUM (2), cnt));
0f2d19dd 1154#else
3ab9f56e
DH
1155 if (bits_to_shift < 0)
1156 /* Signed right shift (SCM_SRS does it right) by abs(cnt) bits. */
1157 return SCM_MAKINUM (SCM_SRS (SCM_INUM (n), -bits_to_shift));
1158 else {
1159 /* Shift left, but make sure not to leave the range of inums */
1160 SCM res = SCM_MAKINUM (SCM_INUM (n) << cnt);
1161 if (SCM_INUM (res) >> cnt != SCM_INUM (n))
1162 scm_num_overflow (FUNC_NAME);
1163 return res;
1164 }
0f2d19dd
JB
1165#endif
1166}
1bbd0b84 1167#undef FUNC_NAME
0f2d19dd 1168
3c9f20f8 1169
a1ec6916 1170SCM_DEFINE (scm_bit_extract, "bit-extract", 3, 0, 0,
1bbd0b84 1171 (SCM n, SCM start, SCM end),
b380b885
MD
1172 "Returns the integer composed of the @var{start} (inclusive) through\n"
1173 "@var{end} (exclusive) bits of @var{n}. The @var{start}th bit becomes\n"
1174 "the 0-th bit in the result.@refill\n\n"
1175 "Example:\n"
1176 "@lisp\n"
1177 "(number->string (bit-extract #b1101101010 0 4) 2)\n"
1178 " @result{} \"1010\"\n"
1179 "(number->string (bit-extract #b1101101010 4 9) 2)\n"
1180 " @result{} \"10110\"\n"
1181 "@end lisp")
1bbd0b84 1182#define FUNC_NAME s_scm_bit_extract
0f2d19dd 1183{
c1bfcf60 1184 int istart, iend;
c1bfcf60
GB
1185 SCM_VALIDATE_INUM_MIN_COPY (2,start,0,istart);
1186 SCM_VALIDATE_INUM_MIN_COPY (3, end, 0, iend);
1187 SCM_ASSERT_RANGE (3, end, (iend >= istart));
78166ad5
DH
1188
1189 if (SCM_INUMP (n)) {
1190 return SCM_MAKINUM ((SCM_INUM (n) >> istart) & ((1L << (iend - istart)) - 1));
1191 } else if (SCM_BIGP (n)) {
1192 SCM num1 = SCM_MAKINUM (1L);
1193 SCM num2 = SCM_MAKINUM (2L);
1194 SCM bits = SCM_MAKINUM (iend - istart);
1195 SCM mask = scm_difference (scm_integer_expt (num2, bits), num1);
1196 return scm_logand (mask, scm_ash (n, SCM_MAKINUM (-istart)));
1197 } else {
1198 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
1199 }
0f2d19dd 1200}
1bbd0b84 1201#undef FUNC_NAME
0f2d19dd 1202
3c9f20f8 1203
e4755e5c
JB
1204static const char scm_logtab[] = {
1205 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
1206};
1cc91f1b 1207
a1ec6916 1208SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0,
1bbd0b84 1209 (SCM n),
b380b885
MD
1210 "Returns the number of bits in integer @var{n}. If integer is positive,\n"
1211 "the 1-bits in its binary representation are counted. If negative, the\n"
1212 "0-bits in its two's-complement binary representation are counted. If 0,\n"
1213 "0 is returned.\n\n"
1214 "Example:\n"
1215 "@lisp\n"
1216 "(logcount #b10101010)\n"
1217 " @result{} 4\n"
1218 "(logcount 0)\n"
1219 " @result{} 0\n"
1220 "(logcount -2)\n"
1221 " @result{} 1\n"
1222 "@end lisp")
1bbd0b84 1223#define FUNC_NAME s_scm_logcount
0f2d19dd 1224{
3c9f20f8
DH
1225 if (SCM_INUMP (n)) {
1226 unsigned long int c = 0;
1227 long int nn = SCM_INUM (n);
1228 if (nn < 0) {
1229 nn = -1 - nn;
1230 };
1231 while (nn) {
1232 c += scm_logtab[15 & nn];
1233 nn >>= 4;
1234 };
1235 return SCM_MAKINUM (c);
1236 } else if (SCM_BIGP (n)) {
1237 if (SCM_BIGSIGN (n)) {
1238 return scm_logcount (scm_difference (SCM_MAKINUM (-1L), n));
1239 } else {
1240 unsigned long int c = 0;
1241 scm_sizet i = SCM_NUMDIGS (n);
1242 SCM_BIGDIG * ds = SCM_BDIGITS (n);
1243 while (i--) {
1244 SCM_BIGDIG d;
1245 for (d = ds[i]; d; d >>= 4) {
f872b822 1246 c += scm_logtab[15 & d];
3c9f20f8
DH
1247 }
1248 }
f872b822
MD
1249 return SCM_MAKINUM (c);
1250 }
3c9f20f8
DH
1251 } else {
1252 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
1253 }
0f2d19dd 1254}
1bbd0b84
GB
1255#undef FUNC_NAME
1256
0f2d19dd 1257
e4755e5c
JB
1258static const char scm_ilentab[] = {
1259 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
1260};
1cc91f1b 1261
a1ec6916 1262SCM_DEFINE (scm_integer_length, "integer-length", 1, 0, 0,
1bbd0b84 1263 (SCM n),
b380b885
MD
1264 "Returns the number of bits neccessary to represent @var{n}.\n\n"
1265 "Example:\n"
1266 "@lisp\n"
1267 "(integer-length #b10101010)\n"
1268 " @result{} 8\n"
1269 "(integer-length 0)\n"
1270 " @result{} 0\n"
1271 "(integer-length #b1111)\n"
1272 " @result{} 4\n"
1273 "@end lisp")
1bbd0b84 1274#define FUNC_NAME s_scm_integer_length
0f2d19dd 1275{
3c9f20f8
DH
1276 if (SCM_INUMP (n)) {
1277 unsigned long int c = 0;
1278 unsigned int l = 4;
1279 long int nn = SCM_INUM (n);
1280 if (nn < 0) {
1281 nn = -1 - nn;
1282 };
1283 while (nn) {
f872b822 1284 c += 4;
3c9f20f8
DH
1285 l = scm_ilentab [15 & nn];
1286 nn >>= 4;
1287 };
1288 return SCM_MAKINUM (c - 4 + l);
1289 } else if (SCM_BIGP (n)) {
1290 if (SCM_BIGSIGN (n)) {
1291 return scm_integer_length (scm_difference (SCM_MAKINUM (-1L), n));
1292 } else {
1293 unsigned long int digs = SCM_NUMDIGS (n) - 1;
1294 unsigned long int c = digs * SCM_BITSPERDIG;
1295 unsigned int l = 4;
1296 SCM_BIGDIG * ds = SCM_BDIGITS (n);
1297 SCM_BIGDIG d = ds [digs];
1298 while (d) {
1299 c += 4;
1300 l = scm_ilentab [15 & d];
1301 d >>= 4;
1302 };
1303 return SCM_MAKINUM (c - 4 + l);
f872b822 1304 }
3c9f20f8
DH
1305 } else {
1306 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
1307 }
0f2d19dd 1308}
1bbd0b84 1309#undef FUNC_NAME
0f2d19dd
JB
1310
1311
1312#ifdef SCM_BIGDIG
e4755e5c 1313static const char s_bignum[] = "bignum";
1cc91f1b 1314
0f2d19dd 1315SCM
1bbd0b84 1316scm_mkbig (scm_sizet nlen, int sign)
0f2d19dd 1317{
c209c88e
GB
1318 SCM v;
1319 /* Cast to long int to avoid signed/unsigned comparison warnings. */
f3ae5d60
MD
1320 if ((( ((long int) nlen) << SCM_BIGSIZEFIELD) >> SCM_BIGSIZEFIELD)
1321 != (long int) nlen)
e4755e5c 1322 scm_wta (SCM_MAKINUM (nlen), (char *) SCM_NALLOC, s_bignum);
c209c88e 1323
f872b822 1324 SCM_NEWCELL (v);
0f2d19dd 1325 SCM_DEFER_INTS;
f872b822 1326 SCM_SETCHARS (v, scm_must_malloc ((long) (nlen * sizeof (SCM_BIGDIG)),
e4755e5c 1327 s_bignum));
f3ae5d60 1328 SCM_SETNUMDIGS (v, nlen, sign);
0f2d19dd
JB
1329 SCM_ALLOW_INTS;
1330 return v;
1331}
1332
1cc91f1b 1333
0f2d19dd 1334SCM
1bbd0b84 1335scm_big2inum (SCM b, scm_sizet l)
0f2d19dd
JB
1336{
1337 unsigned long num = 0;
f872b822
MD
1338 SCM_BIGDIG *tmp = SCM_BDIGITS (b);
1339 while (l--)
1340 num = SCM_BIGUP (num) + tmp[l];
f3ae5d60 1341 if (!SCM_BIGSIGN (b))
f872b822
MD
1342 {
1343 if (SCM_POSFIXABLE (num))
1344 return SCM_MAKINUM (num);
1345 }
894a712b 1346 else if (num <= -SCM_MOST_NEGATIVE_FIXNUM)
f872b822 1347 return SCM_MAKINUM (-num);
0f2d19dd
JB
1348 return b;
1349}
1350
1351
e4755e5c 1352static const char s_adjbig[] = "scm_adjbig";
1cc91f1b 1353
0f2d19dd 1354SCM
1bbd0b84 1355scm_adjbig (SCM b, scm_sizet nlen)
0f2d19dd 1356{
2bf746cc 1357 scm_sizet nsiz = nlen;
f3ae5d60 1358 if (((nsiz << SCM_BIGSIZEFIELD) >> SCM_BIGSIZEFIELD) != nlen)
f872b822 1359 scm_wta (scm_ulong2num (nsiz), (char *) SCM_NALLOC, s_adjbig);
2bf746cc 1360
0f2d19dd 1361 SCM_DEFER_INTS;
2bf746cc
JB
1362 {
1363 SCM_BIGDIG *digits
1364 = ((SCM_BIGDIG *)
f872b822
MD
1365 scm_must_realloc ((char *) SCM_CHARS (b),
1366 (long) (SCM_NUMDIGS (b) * sizeof (SCM_BIGDIG)),
495ffc6e 1367 (long) (nsiz * sizeof (SCM_BIGDIG)), s_bignum));
2bf746cc
JB
1368
1369 SCM_SETCHARS (b, digits);
f3ae5d60 1370 SCM_SETNUMDIGS (b, nsiz, SCM_BIGSIGN (b));
2bf746cc 1371 }
0f2d19dd
JB
1372 SCM_ALLOW_INTS;
1373 return b;
1374}
1375
1376
1cc91f1b 1377
0f2d19dd 1378SCM
1bbd0b84 1379scm_normbig (SCM b)
0f2d19dd 1380{
f872b822
MD
1381#ifndef _UNICOS
1382 scm_sizet nlen = SCM_NUMDIGS (b);
0f2d19dd 1383#else
f872b822 1384 int nlen = SCM_NUMDIGS (b); /* unsigned nlen breaks on Cray when nlen => 0 */
0f2d19dd 1385#endif
f872b822
MD
1386 SCM_BIGDIG *zds = SCM_BDIGITS (b);
1387 while (nlen-- && !zds[nlen]);
1388 nlen++;
1389 if (nlen * SCM_BITSPERDIG / SCM_CHAR_BIT <= sizeof (SCM))
1390 if (SCM_INUMP (b = scm_big2inum (b, (scm_sizet) nlen)))
1391 return b;
1392 if (SCM_NUMDIGS (b) == nlen)
1393 return b;
1394 return scm_adjbig (b, (scm_sizet) nlen);
0f2d19dd
JB
1395}
1396
1397
1cc91f1b 1398
0f2d19dd 1399SCM
1bbd0b84 1400scm_copybig (SCM b, int sign)
0f2d19dd 1401{
f872b822
MD
1402 scm_sizet i = SCM_NUMDIGS (b);
1403 SCM ans = scm_mkbig (i, sign);
1404 SCM_BIGDIG *src = SCM_BDIGITS (b), *dst = SCM_BDIGITS (ans);
1405 while (i--)
1406 dst[i] = src[i];
0f2d19dd
JB
1407 return ans;
1408}
1409
1410
1cc91f1b 1411
0f2d19dd 1412SCM
1bbd0b84 1413scm_long2big (long n)
0f2d19dd
JB
1414{
1415 scm_sizet i = 0;
1416 SCM_BIGDIG *digits;
f872b822
MD
1417 SCM ans = scm_mkbig (SCM_DIGSPERLONG, n < 0);
1418 digits = SCM_BDIGITS (ans);
1419 if (n < 0)
1420 n = -n;
1421 while (i < SCM_DIGSPERLONG)
1422 {
1423 digits[i++] = SCM_BIGLO (n);
1424 n = SCM_BIGDN ((unsigned long) n);
1425 }
0f2d19dd
JB
1426 return ans;
1427}
1428
5c11cc9d 1429#ifdef HAVE_LONG_LONGS
1cc91f1b 1430
0f2d19dd 1431SCM
1bbd0b84 1432scm_long_long2big (long_long n)
0f2d19dd
JB
1433{
1434 scm_sizet i;
1435 SCM_BIGDIG *digits;
1436 SCM ans;
1437 int n_digits;
1438
1439 {
1440 long tn;
1441 tn = (long) n;
f872b822 1442 if ((long long) tn == n)
0f2d19dd
JB
1443 return scm_long2big (tn);
1444 }
1445
1446 {
1447 long_long tn;
1448
1449 for (tn = n, n_digits = 0;
1450 tn;
f872b822 1451 ++n_digits, tn = SCM_BIGDN ((ulong_long) tn))
0f2d19dd
JB
1452 ;
1453 }
1454
1455 i = 0;
f872b822
MD
1456 ans = scm_mkbig (n_digits, n < 0);
1457 digits = SCM_BDIGITS (ans);
0f2d19dd
JB
1458 if (n < 0)
1459 n = -n;
f872b822
MD
1460 while (i < n_digits)
1461 {
1462 digits[i++] = SCM_BIGLO (n);
1463 n = SCM_BIGDN ((ulong_long) n);
1464 }
0f2d19dd
JB
1465 return ans;
1466}
1467#endif
1468
1cc91f1b 1469
0f2d19dd 1470SCM
1bbd0b84 1471scm_2ulong2big (unsigned long *np)
0f2d19dd
JB
1472{
1473 unsigned long n;
1474 scm_sizet i;
1475 SCM_BIGDIG *digits;
1476 SCM ans;
1477
f872b822
MD
1478 ans = scm_mkbig (2 * SCM_DIGSPERLONG, 0);
1479 digits = SCM_BDIGITS (ans);
0f2d19dd
JB
1480
1481 n = np[0];
1482 for (i = 0; i < SCM_DIGSPERLONG; ++i)
1483 {
f872b822
MD
1484 digits[i] = SCM_BIGLO (n);
1485 n = SCM_BIGDN ((unsigned long) n);
0f2d19dd
JB
1486 }
1487 n = np[1];
1488 for (i = 0; i < SCM_DIGSPERLONG; ++i)
1489 {
f872b822
MD
1490 digits[i + SCM_DIGSPERLONG] = SCM_BIGLO (n);
1491 n = SCM_BIGDN ((unsigned long) n);
0f2d19dd
JB
1492 }
1493 return ans;
1494}
1495
1496
1cc91f1b 1497
0f2d19dd 1498SCM
1bbd0b84 1499scm_ulong2big (unsigned long n)
0f2d19dd
JB
1500{
1501 scm_sizet i = 0;
1502 SCM_BIGDIG *digits;
f872b822
MD
1503 SCM ans = scm_mkbig (SCM_DIGSPERLONG, 0);
1504 digits = SCM_BDIGITS (ans);
1505 while (i < SCM_DIGSPERLONG)
1506 {
1507 digits[i++] = SCM_BIGLO (n);
1508 n = SCM_BIGDN (n);
1509 }
0f2d19dd
JB
1510 return ans;
1511}
1512
1513
1cc91f1b 1514
0f2d19dd 1515int
1bbd0b84 1516scm_bigcomp (SCM x, SCM y)
0f2d19dd 1517{
f872b822
MD
1518 int xsign = SCM_BIGSIGN (x);
1519 int ysign = SCM_BIGSIGN (y);
0f2d19dd 1520 scm_sizet xlen, ylen;
2bf746cc
JB
1521
1522 /* Look at the signs, first. */
f872b822
MD
1523 if (ysign < xsign)
1524 return 1;
1525 if (ysign > xsign)
1526 return -1;
2bf746cc
JB
1527
1528 /* They're the same sign, so see which one has more digits. Note
1529 that, if they are negative, the longer number is the lesser. */
f872b822
MD
1530 ylen = SCM_NUMDIGS (y);
1531 xlen = SCM_NUMDIGS (x);
2bf746cc
JB
1532 if (ylen > xlen)
1533 return (xsign) ? -1 : 1;
f872b822
MD
1534 if (ylen < xlen)
1535 return (xsign) ? 1 : -1;
2bf746cc
JB
1536
1537 /* They have the same number of digits, so find the most significant
1538 digit where they differ. */
1539 while (xlen)
1540 {
1541 --xlen;
1542 if (SCM_BDIGITS (y)[xlen] != SCM_BDIGITS (x)[xlen])
1543 /* Make the discrimination based on the digit that differs. */
f872b822
MD
1544 return ((SCM_BDIGITS (y)[xlen] > SCM_BDIGITS (x)[xlen])
1545 ? (xsign ? -1 : 1)
1546 : (xsign ? 1 : -1));
2bf746cc
JB
1547 }
1548
1549 /* The numbers are identical. */
1550 return 0;
0f2d19dd
JB
1551}
1552
1553#ifndef SCM_DIGSTOOBIG
1554
1cc91f1b 1555
0f2d19dd 1556long
1bbd0b84 1557scm_pseudolong (long x)
0f2d19dd 1558{
f872b822
MD
1559 union
1560 {
0f2d19dd
JB
1561 long l;
1562 SCM_BIGDIG bd[SCM_DIGSPERLONG];
f872b822
MD
1563 }
1564 p;
0f2d19dd 1565 scm_sizet i = 0;
f872b822
MD
1566 if (x < 0)
1567 x = -x;
1568 while (i < SCM_DIGSPERLONG)
1569 {
1570 p.bd[i++] = SCM_BIGLO (x);
1571 x = SCM_BIGDN (x);
1572 }
0f2d19dd
JB
1573 /* p.bd[0] = SCM_BIGLO(x); p.bd[1] = SCM_BIGDN(x); */
1574 return p.l;
1575}
1576
1577#else
1578
1cc91f1b 1579
0f2d19dd 1580void
1bbd0b84 1581scm_longdigs (long x, SCM_BIGDIG digs[])
0f2d19dd
JB
1582{
1583 scm_sizet i = 0;
f872b822
MD
1584 if (x < 0)
1585 x = -x;
1586 while (i < SCM_DIGSPERLONG)
1587 {
1588 digs[i++] = SCM_BIGLO (x);
1589 x = SCM_BIGDN (x);
1590 }
0f2d19dd
JB
1591}
1592#endif
1593
1594
1cc91f1b 1595
0f2d19dd 1596SCM
1bbd0b84 1597scm_addbig (SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy, int sgny)
0f2d19dd
JB
1598{
1599 /* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60 1600 /* Assumes xsgn and sgny scm_equal either 0 or SCM_BIGSIGNFLAG */
0f2d19dd 1601 long num = 0;
f872b822
MD
1602 scm_sizet i = 0, ny = SCM_NUMDIGS (bigy);
1603 SCM z = scm_copybig (bigy, SCM_BIGSIGN (bigy) ^ sgny);
1604 SCM_BIGDIG *zds = SCM_BDIGITS (z);
1605 if (xsgn ^ SCM_BIGSIGN (z))
1606 {
1607 do
1608 {
1609 num += (long) zds[i] - x[i];
1610 if (num < 0)
1611 {
1612 zds[i] = num + SCM_BIGRAD;
1613 num = -1;
1614 }
1615 else
1616 {
1617 zds[i] = SCM_BIGLO (num);
1618 num = 0;
1619 }
1620 }
1621 while (++i < nx);
1622 if (num && nx == ny)
1623 {
1624 num = 1;
1625 i = 0;
4260a7fc 1626 SCM_SET_CELL_WORD_0 (z, SCM_CELL_WORD_0 (z) ^ SCM_BIGSIGNFLAG);
f872b822
MD
1627 do
1628 {
1629 num += (SCM_BIGRAD - 1) - zds[i];
1630 zds[i++] = SCM_BIGLO (num);
1631 num = SCM_BIGDN (num);
1632 }
1633 while (i < ny);
1634 }
1635 else
1636 while (i < ny)
1637 {
1638 num += zds[i];
1639 if (num < 0)
1640 {
1641 zds[i++] = num + SCM_BIGRAD;
1642 num = -1;
1643 }
1644 else
1645 {
1646 zds[i++] = SCM_BIGLO (num);
1647 num = 0;
1648 }
1649 }
1650 }
1651 else
1652 {
1653 do
1654 {
1655 num += (long) zds[i] + x[i];
1656 zds[i++] = SCM_BIGLO (num);
1657 num = SCM_BIGDN (num);
1658 }
1659 while (i < nx);
1660 if (!num)
1661 return z;
1662 while (i < ny)
1663 {
1664 num += zds[i];
1665 zds[i++] = SCM_BIGLO (num);
1666 num = SCM_BIGDN (num);
1667 if (!num)
1668 return z;
1669 }
1670 if (num)
1671 {
1672 z = scm_adjbig (z, ny + 1);
1673 SCM_BDIGITS (z)[ny] = num;
1674 return z;
1675 }
1676 }
1677 return scm_normbig (z);
0f2d19dd
JB
1678}
1679
1cc91f1b 1680
0f2d19dd 1681SCM
1bbd0b84 1682scm_mulbig (SCM_BIGDIG *x, scm_sizet nx, SCM_BIGDIG *y, scm_sizet ny, int sgn)
0f2d19dd
JB
1683{
1684 scm_sizet i = 0, j = nx + ny;
1685 unsigned long n = 0;
f872b822
MD
1686 SCM z = scm_mkbig (j, sgn);
1687 SCM_BIGDIG *zds = SCM_BDIGITS (z);
1688 while (j--)
1689 zds[j] = 0;
1690 do
1691 {
1692 j = 0;
1693 if (x[i])
1694 {
1695 do
1696 {
1697 n += zds[i + j] + ((unsigned long) x[i] * y[j]);
1698 zds[i + j++] = SCM_BIGLO (n);
1699 n = SCM_BIGDN (n);
1700 }
1701 while (j < ny);
1702 if (n)
1703 {
1704 zds[i + j] = n;
1705 n = 0;
1706 }
1707 }
0f2d19dd 1708 }
f872b822
MD
1709 while (++i < nx);
1710 return scm_normbig (z);
0f2d19dd
JB
1711}
1712
1cc91f1b 1713
0f2d19dd 1714unsigned int
bb628794 1715scm_divbigdig (SCM_BIGDIG * ds, scm_sizet h, SCM_BIGDIG div)
0f2d19dd
JB
1716{
1717 register unsigned long t2 = 0;
f872b822
MD
1718 while (h--)
1719 {
1720 t2 = SCM_BIGUP (t2) + ds[h];
1721 ds[h] = t2 / div;
1722 t2 %= div;
1723 }
0f2d19dd
JB
1724 return t2;
1725}
1726
1727
1cc91f1b 1728
f4c627b3 1729static SCM
1bbd0b84 1730scm_divbigint (SCM x, long z, int sgn, int mode)
0f2d19dd 1731{
f872b822
MD
1732 if (z < 0)
1733 z = -z;
1734 if (z < SCM_BIGRAD)
1735 {
1736 register unsigned long t2 = 0;
1737 register SCM_BIGDIG *ds = SCM_BDIGITS (x);
1738 scm_sizet nd = SCM_NUMDIGS (x);
1739 while (nd--)
1740 t2 = (SCM_BIGUP (t2) + ds[nd]) % z;
1741 if (mode && t2)
1742 t2 = z - t2;
1743 return SCM_MAKINUM (sgn ? -t2 : t2);
1744 }
0f2d19dd
JB
1745 {
1746#ifndef SCM_DIGSTOOBIG
f872b822
MD
1747 unsigned long t2 = scm_pseudolong (z);
1748 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
1749 (SCM_BIGDIG *) & t2, SCM_DIGSPERLONG,
1750 sgn, mode);
0f2d19dd
JB
1751#else
1752 SCM_BIGDIG t2[SCM_DIGSPERLONG];
f872b822
MD
1753 scm_longdigs (z, t2);
1754 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
1755 t2, SCM_DIGSPERLONG,
1756 sgn, mode);
0f2d19dd
JB
1757#endif
1758 }
1759}
1760
1cc91f1b 1761
f4c627b3 1762static SCM
1bbd0b84 1763scm_divbigbig (SCM_BIGDIG *x, scm_sizet nx, SCM_BIGDIG *y, scm_sizet ny, int sgn, int modes)
0f2d19dd
JB
1764{
1765 /* modes description
f872b822
MD
1766 0 remainder
1767 1 scm_modulo
1768 2 quotient
f4c627b3 1769 3 quotient but returns SCM_UNDEFINED if division is not exact. */
0f2d19dd
JB
1770 scm_sizet i = 0, j = 0;
1771 long num = 0;
1772 unsigned long t2 = 0;
1773 SCM z, newy;
f872b822 1774 SCM_BIGDIG d = 0, qhat, *zds, *yds;
0f2d19dd
JB
1775 /* algorithm requires nx >= ny */
1776 if (nx < ny)
f872b822
MD
1777 switch (modes)
1778 {
1779 case 0: /* remainder -- just return x */
1780 z = scm_mkbig (nx, sgn);
1781 zds = SCM_BDIGITS (z);
1782 do
1783 {
1784 zds[i] = x[i];
1785 }
1786 while (++i < nx);
1787 return z;
1788 case 1: /* scm_modulo -- return y-x */
1789 z = scm_mkbig (ny, sgn);
1790 zds = SCM_BDIGITS (z);
1791 do
1792 {
1793 num += (long) y[i] - x[i];
1794 if (num < 0)
1795 {
1796 zds[i] = num + SCM_BIGRAD;
1797 num = -1;
1798 }
1799 else
1800 {
1801 zds[i] = num;
1802 num = 0;
1803 }
1804 }
1805 while (++i < nx);
1806 while (i < ny)
1807 {
1808 num += y[i];
1809 if (num < 0)
1810 {
1811 zds[i++] = num + SCM_BIGRAD;
1812 num = -1;
1813 }
1814 else
1815 {
1816 zds[i++] = num;
1817 num = 0;
1818 }
1819 }
1820 goto doadj;
1821 case 2:
1822 return SCM_INUM0; /* quotient is zero */
1823 case 3:
f4c627b3 1824 return SCM_UNDEFINED; /* the division is not exact */
0f2d19dd 1825 }
f872b822
MD
1826
1827 z = scm_mkbig (nx == ny ? nx + 2 : nx + 1, sgn);
1828 zds = SCM_BDIGITS (z);
1829 if (nx == ny)
1830 zds[nx + 1] = 0;
1831 while (!y[ny - 1])
1832 ny--; /* in case y came in as a psuedolong */
1833 if (y[ny - 1] < (SCM_BIGRAD >> 1))
1834 { /* normalize operands */
1835 d = SCM_BIGRAD / (y[ny - 1] + 1);
1836 newy = scm_mkbig (ny, 0);
1837 yds = SCM_BDIGITS (newy);
1838 while (j < ny)
1839 {
1840 t2 += (unsigned long) y[j] * d;
1841 yds[j++] = SCM_BIGLO (t2);
1842 t2 = SCM_BIGDN (t2);
1843 }
1844 y = yds;
1845 j = 0;
1846 t2 = 0;
1847 while (j < nx)
1848 {
1849 t2 += (unsigned long) x[j] * d;
1850 zds[j++] = SCM_BIGLO (t2);
1851 t2 = SCM_BIGDN (t2);
1852 }
1853 zds[j] = t2;
1854 }
1855 else
1856 {
1857 zds[j = nx] = 0;
1858 while (j--)
1859 zds[j] = x[j];
1860 }
1861 j = nx == ny ? nx + 1 : nx; /* dividend needs more digits than divisor */
1862 do
1863 { /* loop over digits of quotient */
1864 if (zds[j] == y[ny - 1])
1865 qhat = SCM_BIGRAD - 1;
1866 else
1867 qhat = (SCM_BIGUP (zds[j]) + zds[j - 1]) / y[ny - 1];
1868 if (!qhat)
1869 continue;
1870 i = 0;
1871 num = 0;
1872 t2 = 0;
1873 do
1874 { /* multiply and subtract */
1875 t2 += (unsigned long) y[i] * qhat;
1876 num += zds[j - ny + i] - SCM_BIGLO (t2);
1877 if (num < 0)
1878 {
1879 zds[j - ny + i] = num + SCM_BIGRAD;
1880 num = -1;
1881 }
1882 else
1883 {
1884 zds[j - ny + i] = num;
1885 num = 0;
1886 }
1887 t2 = SCM_BIGDN (t2);
1888 }
1889 while (++i < ny);
1890 num += zds[j - ny + i] - t2; /* borrow from high digit; don't update */
1891 while (num)
1892 { /* "add back" required */
1893 i = 0;
1894 num = 0;
1895 qhat--;
1896 do
1897 {
1898 num += (long) zds[j - ny + i] + y[i];
1899 zds[j - ny + i] = SCM_BIGLO (num);
1900 num = SCM_BIGDN (num);
1901 }
1902 while (++i < ny);
1903 num--;
1904 }
1905 if (modes & 2)
1906 zds[j] = qhat;
1907 }
1908 while (--j >= ny);
1909 switch (modes)
1910 {
1911 case 3: /* check that remainder==0 */
1912 for (j = ny; j && !zds[j - 1]; --j);
1913 if (j)
f4c627b3 1914 return SCM_UNDEFINED;
f872b822
MD
1915 case 2: /* move quotient down in z */
1916 j = (nx == ny ? nx + 2 : nx + 1) - ny;
1917 for (i = 0; i < j; i++)
1918 zds[i] = zds[i + ny];
1919 ny = i;
1920 break;
1921 case 1: /* subtract for scm_modulo */
1922 i = 0;
1923 num = 0;
1924 j = 0;
1925 do
1926 {
1927 num += y[i] - zds[i];
1928 j = j | zds[i];
1929 if (num < 0)
1930 {
1931 zds[i] = num + SCM_BIGRAD;
1932 num = -1;
1933 }
1934 else
1935 {
1936 zds[i] = num;
1937 num = 0;
1938 }
1939 }
1940 while (++i < ny);
1941 if (!j)
1942 return SCM_INUM0;
1943 case 0: /* just normalize remainder */
1944 if (d)
1945 scm_divbigdig (zds, ny, d);
1946 }
0f2d19dd 1947 doadj:
f872b822
MD
1948 for (j = ny; j && !zds[j - 1]; --j);
1949 if (j * SCM_BITSPERDIG <= sizeof (SCM) * SCM_CHAR_BIT)
1950 if (SCM_INUMP (z = scm_big2inum (z, j)))
1951 return z;
1952 return scm_adjbig (z, j);
0f2d19dd
JB
1953}
1954#endif
f872b822 1955\f
0f2d19dd
JB
1956
1957
1958
0f2d19dd
JB
1959
1960/*** NUMBERS -> STRINGS ***/
0f2d19dd 1961int scm_dblprec;
e4755e5c 1962static const double fx[] =
f872b822
MD
1963{ 0.0, 5e-1, 5e-2, 5e-3, 5e-4, 5e-5,
1964 5e-6, 5e-7, 5e-8, 5e-9, 5e-10,
1965 5e-11, 5e-12, 5e-13, 5e-14, 5e-15,
1966 5e-16, 5e-17, 5e-18, 5e-19, 5e-20};
0f2d19dd
JB
1967
1968
1969
1cc91f1b 1970
0f2d19dd 1971static scm_sizet
1bbd0b84 1972idbl2str (double f, char *a)
0f2d19dd
JB
1973{
1974 int efmt, dpt, d, i, wp = scm_dblprec;
1975 scm_sizet ch = 0;
1976 int exp = 0;
1977
f872b822
MD
1978 if (f == 0.0)
1979 goto zero; /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;} */
1980 if (f < 0.0)
1981 {
1982 f = -f;
1983 a[ch++] = '-';
1984 }
1985 else if (f > 0.0);
1986 else
1987 goto funny;
1988 if (IS_INF (f))
1989 {
1990 if (ch == 0)
1991 a[ch++] = '+';
1992 funny:
1993 a[ch++] = '#';
1994 a[ch++] = '.';
1995 a[ch++] = '#';
1996 return ch;
1997 }
1998#ifdef DBL_MIN_10_EXP /* Prevent unnormalized values, as from
1999 make-uniform-vector, from causing infinite loops. */
2000 while (f < 1.0)
2001 {
2002 f *= 10.0;
2003 if (exp-- < DBL_MIN_10_EXP)
2004 goto funny;
2005 }
2006 while (f > 10.0)
2007 {
2008 f *= 0.10;
2009 if (exp++ > DBL_MAX_10_EXP)
2010 goto funny;
2011 }
2012#else
2013 while (f < 1.0)
2014 {
2015 f *= 10.0;
2016 exp--;
2017 }
2018 while (f > 10.0)
2019 {
2020 f /= 10.0;
2021 exp++;
2022 }
2023#endif
2024 if (f + fx[wp] >= 10.0)
2025 {
2026 f = 1.0;
2027 exp++;
2028 }
0f2d19dd 2029 zero:
f872b822
MD
2030#ifdef ENGNOT
2031 dpt = (exp + 9999) % 3;
0f2d19dd
JB
2032 exp -= dpt++;
2033 efmt = 1;
f872b822
MD
2034#else
2035 efmt = (exp < -3) || (exp > wp + 2);
0f2d19dd 2036 if (!efmt)
cda139a7
MD
2037 {
2038 if (exp < 0)
2039 {
2040 a[ch++] = '0';
2041 a[ch++] = '.';
2042 dpt = exp;
f872b822
MD
2043 while (++dpt)
2044 a[ch++] = '0';
cda139a7
MD
2045 }
2046 else
f872b822 2047 dpt = exp + 1;
cda139a7 2048 }
0f2d19dd
JB
2049 else
2050 dpt = 1;
f872b822
MD
2051#endif
2052
2053 do
2054 {
2055 d = f;
2056 f -= d;
2057 a[ch++] = d + '0';
2058 if (f < fx[wp])
2059 break;
2060 if (f + fx[wp] >= 1.0)
2061 {
2062 a[ch - 1]++;
2063 break;
2064 }
2065 f *= 10.0;
2066 if (!(--dpt))
2067 a[ch++] = '.';
0f2d19dd 2068 }
f872b822 2069 while (wp--);
0f2d19dd
JB
2070
2071 if (dpt > 0)
cda139a7 2072 {
f872b822 2073#ifndef ENGNOT
cda139a7
MD
2074 if ((dpt > 4) && (exp > 6))
2075 {
f872b822 2076 d = (a[0] == '-' ? 2 : 1);
cda139a7 2077 for (i = ch++; i > d; i--)
f872b822 2078 a[i] = a[i - 1];
cda139a7
MD
2079 a[d] = '.';
2080 efmt = 1;
2081 }
2082 else
f872b822 2083#endif
cda139a7 2084 {
f872b822
MD
2085 while (--dpt)
2086 a[ch++] = '0';
cda139a7
MD
2087 a[ch++] = '.';
2088 }
2089 }
f872b822
MD
2090 if (a[ch - 1] == '.')
2091 a[ch++] = '0'; /* trailing zero */
2092 if (efmt && exp)
2093 {
2094 a[ch++] = 'e';
2095 if (exp < 0)
2096 {
2097 exp = -exp;
2098 a[ch++] = '-';
2099 }
2100 for (i = 10; i <= exp; i *= 10);
2101 for (i /= 10; i; i /= 10)
2102 {
2103 a[ch++] = exp / i + '0';
2104 exp %= i;
2105 }
0f2d19dd 2106 }
0f2d19dd
JB
2107 return ch;
2108}
2109
1cc91f1b 2110
0f2d19dd 2111static scm_sizet
1bbd0b84 2112iflo2str (SCM flt, char *str)
0f2d19dd
JB
2113{
2114 scm_sizet i;
f3ae5d60
MD
2115 if (SCM_SLOPPY_REALP (flt))
2116 i = idbl2str (SCM_REAL_VALUE (flt), str);
0f2d19dd 2117 else
f872b822 2118 {
f3ae5d60
MD
2119 i = idbl2str (SCM_COMPLEX_REAL (flt), str);
2120 if (SCM_COMPLEX_IMAG (flt) != 0.0)
2121 {
2122 if (0 <= SCM_COMPLEX_IMAG (flt))
2123 str[i++] = '+';
2124 i += idbl2str (SCM_COMPLEX_IMAG (flt), &str[i]);
2125 str[i++] = 'i';
2126 }
f872b822 2127 }
0f2d19dd
JB
2128 return i;
2129}
0f2d19dd 2130
5c11cc9d 2131/* convert a long to a string (unterminated). returns the number of
1bbd0b84
GB
2132 characters in the result.
2133 rad is output base
2134 p is destination: worst case (base 2) is SCM_INTBUFLEN */
0f2d19dd 2135scm_sizet
1bbd0b84 2136scm_iint2str (long num, int rad, char *p)
0f2d19dd 2137{
5c11cc9d
GH
2138 scm_sizet j = 1;
2139 scm_sizet i;
2140 unsigned long n = (num < 0) ? -num : num;
2141
f872b822 2142 for (n /= rad; n > 0; n /= rad)
5c11cc9d
GH
2143 j++;
2144
2145 i = j;
2146 if (num < 0)
f872b822 2147 {
f872b822 2148 *p++ = '-';
5c11cc9d
GH
2149 j++;
2150 n = -num;
f872b822 2151 }
5c11cc9d
GH
2152 else
2153 n = num;
f872b822
MD
2154 while (i--)
2155 {
5c11cc9d
GH
2156 int d = n % rad;
2157
f872b822
MD
2158 n /= rad;
2159 p[i] = d + ((d < 10) ? '0' : 'a' - 10);
2160 }
0f2d19dd
JB
2161 return j;
2162}
2163
2164
2165#ifdef SCM_BIGDIG
1cc91f1b 2166
0f2d19dd 2167static SCM
1bbd0b84 2168big2str (SCM b, unsigned int radix)
0f2d19dd 2169{
f872b822
MD
2170 SCM t = scm_copybig (b, 0); /* sign of temp doesn't matter */
2171 register SCM_BIGDIG *ds = SCM_BDIGITS (t);
2172 scm_sizet i = SCM_NUMDIGS (t);
2173 scm_sizet j = radix == 16 ? (SCM_BITSPERDIG * i) / 4 + 2
2174 : radix >= 10 ? (SCM_BITSPERDIG * i * 241L) / 800 + 2
2175 : (SCM_BITSPERDIG * i) + 2;
0f2d19dd
JB
2176 scm_sizet k = 0;
2177 scm_sizet radct = 0;
2178 scm_sizet ch; /* jeh */
2179 SCM_BIGDIG radpow = 1, radmod = 0;
f872b822
MD
2180 SCM ss = scm_makstr ((long) j, 0);
2181 char *s = SCM_CHARS (ss), c;
2182 while ((long) radpow * radix < SCM_BIGRAD)
2183 {
2184 radpow *= radix;
2185 radct++;
2186 }
f3ae5d60 2187 s[0] = SCM_BIGSIGN (b) ? '-' : '+';
f872b822
MD
2188 while ((i || radmod) && j)
2189 {
2190 if (k == 0)
2191 {
2192 radmod = (SCM_BIGDIG) scm_divbigdig (ds, i, radpow);
2193 k = radct;
2194 if (!ds[i - 1])
2195 i--;
2196 }
2197 c = radmod % radix;
2198 radmod /= radix;
2199 k--;
2200 s[--j] = c < 10 ? c + '0' : c + 'a' - 10;
2201 }
0f2d19dd 2202 ch = s[0] == '-' ? 1 : 0; /* jeh */
f872b822
MD
2203 if (ch < j)
2204 { /* jeh */
2205 for (i = j; j < SCM_LENGTH (ss); j++)
2206 s[ch + j - i] = s[j]; /* jeh */
2207 scm_vector_set_length_x (ss, /* jeh */
4260a7fc 2208 SCM_MAKINUM (ch + SCM_LENGTH (ss) - i));
f872b822 2209 }
b098016b
JB
2210
2211 return scm_return_first (ss, t);
0f2d19dd
JB
2212}
2213#endif
2214
2215
a1ec6916 2216SCM_DEFINE (scm_number_to_string, "number->string", 1, 1, 0,
bb628794
DH
2217 (SCM n, SCM radix),
2218 "Return a string holding the external representation of the\n"
2219 "number N in the given RADIX. If N is inexact, a radix of 10\n"
2220 "will be used.")
1bbd0b84 2221#define FUNC_NAME s_scm_number_to_string
0f2d19dd 2222{
1bbd0b84 2223 int base;
98cb6e75
DH
2224
2225 if (SCM_UNBNDP (radix)) {
2226 base = 10;
2227 } else {
2228 SCM_VALIDATE_INUM (2, radix);
2229 base = SCM_INUM (radix);
2230 SCM_ASSERT_RANGE (2, radix, base >= 2);
2231 }
2232
bb628794 2233 if (SCM_INUMP (n)) {
98cb6e75 2234 char num_buf [SCM_INTBUFLEN];
bb628794 2235 scm_sizet length = scm_iint2str (SCM_INUM (n), base, num_buf);
98cb6e75 2236 return scm_makfromstr (num_buf, length, 0);
bb628794
DH
2237 } else if (SCM_BIGP (n)) {
2238 return big2str (n, (unsigned int) base);
2239 } else if (SCM_INEXACTP (n)) {
98cb6e75 2240 char num_buf [SCM_FLOBUFLEN];
bb628794 2241 return scm_makfromstr (num_buf, iflo2str (n, num_buf), 0);
98cb6e75 2242 } else {
bb628794 2243 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd
JB
2244 }
2245}
1bbd0b84 2246#undef FUNC_NAME
0f2d19dd
JB
2247
2248
2249/* These print routines are stubbed here so that scm_repl.c doesn't need
f3ae5d60 2250 SCM_BIGDIG conditionals */
1cc91f1b 2251
0f2d19dd 2252int
f3ae5d60 2253scm_print_real (SCM sexp, SCM port, scm_print_state *pstate)
0f2d19dd 2254{
0f2d19dd 2255 char num_buf[SCM_FLOBUFLEN];
f872b822 2256 scm_lfwrite (num_buf, iflo2str (sexp, num_buf), port);
0f2d19dd
JB
2257 return !0;
2258}
2259
f3ae5d60
MD
2260int
2261scm_print_complex (SCM sexp, SCM port, scm_print_state *pstate)
2262{
2263 char num_buf[SCM_FLOBUFLEN];
2264 scm_lfwrite (num_buf, iflo2str (sexp, num_buf), port);
2265 return !0;
2266}
1cc91f1b 2267
0f2d19dd 2268int
1bbd0b84 2269scm_bigprint (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd
JB
2270{
2271#ifdef SCM_BIGDIG
f872b822
MD
2272 exp = big2str (exp, (unsigned int) 10);
2273 scm_lfwrite (SCM_CHARS (exp), (scm_sizet) SCM_LENGTH (exp), port);
0f2d19dd 2274#else
f872b822 2275 scm_ipruk ("bignum", exp, port);
0f2d19dd
JB
2276#endif
2277 return !0;
2278}
2279/*** END nums->strs ***/
2280
2281/*** STRINGS -> NUMBERS ***/
2a8fecee
JB
2282
2283static SCM
1bbd0b84 2284scm_small_istr2int (char *str, long len, long radix)
2a8fecee
JB
2285{
2286 register long n = 0, ln;
2287 register int c;
2288 register int i = 0;
2289 int lead_neg = 0;
f872b822
MD
2290 if (0 >= len)
2291 return SCM_BOOL_F; /* zero scm_length */
2292 switch (*str)
2293 { /* leading sign */
2294 case '-':
2295 lead_neg = 1;
2296 case '+':
2297 if (++i == len)
2298 return SCM_BOOL_F; /* bad if lone `+' or `-' */
2299 }
2a8fecee 2300
f872b822
MD
2301 do
2302 {
2303 switch (c = str[i++])
2304 {
2305 case DIGITS:
2306 c = c - '0';
2307 goto accumulate;
2308 case 'A':
2309 case 'B':
2310 case 'C':
2311 case 'D':
2312 case 'E':
2313 case 'F':
2314 c = c - 'A' + 10;
2315 goto accumulate;
2316 case 'a':
2317 case 'b':
2318 case 'c':
2319 case 'd':
2320 case 'e':
2321 case 'f':
2322 c = c - 'a' + 10;
2323 accumulate:
2324 if (c >= radix)
2325 return SCM_BOOL_F; /* bad digit for radix */
2326 ln = n;
2327 n = n * radix - c;
2328 /* Negation is a workaround for HP700 cc bug */
2329 if (n > ln || (-n > -SCM_MOST_NEGATIVE_FIXNUM))
2330 goto ovfl;
2331 break;
2332 default:
2333 return SCM_BOOL_F; /* not a digit */
2334 }
2a8fecee 2335 }
f872b822
MD
2336 while (i < len);
2337 if (!lead_neg)
2338 if ((n = -n) > SCM_MOST_POSITIVE_FIXNUM)
2339 goto ovfl;
2340 return SCM_MAKINUM (n);
2a8fecee
JB
2341 ovfl: /* overflow scheme integer */
2342 return SCM_BOOL_F;
2343}
2344
2345
1cc91f1b 2346
0f2d19dd 2347SCM
1bbd0b84 2348scm_istr2int (char *str, long len, long radix)
0f2d19dd
JB
2349{
2350 scm_sizet j;
2351 register scm_sizet k, blen = 1;
2352 scm_sizet i = 0;
2353 int c;
2354 SCM res;
2355 register SCM_BIGDIG *ds;
2356 register unsigned long t2;
2357
f872b822
MD
2358 if (0 >= len)
2359 return SCM_BOOL_F; /* zero scm_length */
2a8fecee
JB
2360
2361 /* Short numbers we parse directly into an int, to avoid the overhead
2362 of creating a bignum. */
2363 if (len < 6)
2364 return scm_small_istr2int (str, len, radix);
2365
f872b822
MD
2366 if (16 == radix)
2367 j = 1 + (4 * len * sizeof (char)) / (SCM_BITSPERDIG);
0f2d19dd 2368 else if (10 <= radix)
f872b822
MD
2369 j = 1 + (84 * len * sizeof (char)) / (SCM_BITSPERDIG * 25);
2370 else
2371 j = 1 + (len * sizeof (char)) / (SCM_BITSPERDIG);
2372 switch (str[0])
2373 { /* leading sign */
2374 case '-':
2375 case '+':
2376 if (++i == (unsigned) len)
2377 return SCM_BOOL_F; /* bad if lone `+' or `-' */
2378 }
2379 res = scm_mkbig (j, '-' == str[0]);
2380 ds = SCM_BDIGITS (res);
2381 for (k = j; k--;)
2382 ds[k] = 0;
2383 do
2384 {
2385 switch (c = str[i++])
2386 {
2387 case DIGITS:
2388 c = c - '0';
2389 goto accumulate;
2390 case 'A':
2391 case 'B':
2392 case 'C':
2393 case 'D':
2394 case 'E':
2395 case 'F':
2396 c = c - 'A' + 10;
2397 goto accumulate;
2398 case 'a':
2399 case 'b':
2400 case 'c':
2401 case 'd':
2402 case 'e':
2403 case 'f':
2404 c = c - 'a' + 10;
2405 accumulate:
2406 if (c >= radix)
2407 return SCM_BOOL_F; /* bad digit for radix */
2408 k = 0;
2409 t2 = c;
2410 moretodo:
2411 while (k < blen)
2412 {
2413/* printf ("k = %d, blen = %d, t2 = %ld, ds[k] = %d\n", k, blen, t2, ds[k]); */
2414 t2 += ds[k] * radix;
2415 ds[k++] = SCM_BIGLO (t2);
2416 t2 = SCM_BIGDN (t2);
2417 }
2418 if (blen > j)
2419 scm_num_overflow ("bignum");
2420 if (t2)
2421 {
2422 blen++;
2423 goto moretodo;
2424 }
2425 break;
2426 default:
2427 return SCM_BOOL_F; /* not a digit */
2428 }
0f2d19dd 2429 }
f872b822
MD
2430 while (i < (unsigned) len);
2431 if (blen * SCM_BITSPERDIG / SCM_CHAR_BIT <= sizeof (SCM))
2432 if (SCM_INUMP (res = scm_big2inum (res, blen)))
2433 return res;
2434 if (j == blen)
2435 return res;
2436 return scm_adjbig (res, blen);
0f2d19dd 2437}
0f2d19dd 2438
0f2d19dd 2439SCM
1bbd0b84 2440scm_istr2flo (char *str, long len, long radix)
0f2d19dd
JB
2441{
2442 register int c, i = 0;
2443 double lead_sgn;
2444 double res = 0.0, tmp = 0.0;
2445 int flg = 0;
2446 int point = 0;
2447 SCM second;
2448
f872b822
MD
2449 if (i >= len)
2450 return SCM_BOOL_F; /* zero scm_length */
0f2d19dd 2451
f872b822
MD
2452 switch (*str)
2453 { /* leading sign */
2454 case '-':
2455 lead_sgn = -1.0;
2456 i++;
2457 break;
2458 case '+':
2459 lead_sgn = 1.0;
2460 i++;
0f2d19dd
JB
2461 break;
2462 default:
f872b822 2463 lead_sgn = 0.0;
0f2d19dd 2464 }
f872b822
MD
2465 if (i == len)
2466 return SCM_BOOL_F; /* bad if lone `+' or `-' */
2467
2468 if (str[i] == 'i' || str[i] == 'I')
2469 { /* handle `+i' and `-i' */
2470 if (lead_sgn == 0.0)
2471 return SCM_BOOL_F; /* must have leading sign */
2472 if (++i < len)
2473 return SCM_BOOL_F; /* `i' not last character */
f8de44c1 2474 return scm_make_complex (0.0, lead_sgn);
f872b822
MD
2475 }
2476 do
2477 { /* check initial digits */
2478 switch (c = str[i])
2479 {
2480 case DIGITS:
2481 c = c - '0';
2482 goto accum1;
2483 case 'D':
2484 case 'E':
2485 case 'F':
2486 if (radix == 10)
2487 goto out1; /* must be exponent */
2488 case 'A':
2489 case 'B':
2490 case 'C':
2491 c = c - 'A' + 10;
2492 goto accum1;
2493 case 'd':
2494 case 'e':
2495 case 'f':
2496 if (radix == 10)
2497 goto out1;
2498 case 'a':
2499 case 'b':
2500 case 'c':
2501 c = c - 'a' + 10;
2502 accum1:
2503 if (c >= radix)
2504 return SCM_BOOL_F; /* bad digit for radix */
2505 res = res * radix + c;
2506 flg = 1; /* res is valid */
2507 break;
2508 default:
2509 goto out1;
2510 }
2511 }
2512 while (++i < len);
0f2d19dd
JB
2513 out1:
2514
2515 /* if true, then we did see a digit above, and res is valid */
f872b822
MD
2516 if (i == len)
2517 goto done;
0f2d19dd
JB
2518
2519 /* By here, must have seen a digit,
2520 or must have next char be a `.' with radix==10 */
2521 if (!flg)
f872b822 2522 if (!(str[i] == '.' && radix == 10))
0f2d19dd
JB
2523 return SCM_BOOL_F;
2524
f872b822
MD
2525 while (str[i] == '#')
2526 { /* optional sharps */
2527 res *= radix;
2528 if (++i == len)
2529 goto done;
0f2d19dd 2530 }
0f2d19dd 2531
f872b822
MD
2532 if (str[i] == '/')
2533 {
2534 while (++i < len)
2535 {
2536 switch (c = str[i])
2537 {
2538 case DIGITS:
2539 c = c - '0';
2540 goto accum2;
2541 case 'A':
2542 case 'B':
2543 case 'C':
2544 case 'D':
2545 case 'E':
2546 case 'F':
2547 c = c - 'A' + 10;
2548 goto accum2;
2549 case 'a':
2550 case 'b':
2551 case 'c':
2552 case 'd':
2553 case 'e':
2554 case 'f':
2555 c = c - 'a' + 10;
2556 accum2:
2557 if (c >= radix)
2558 return SCM_BOOL_F;
2559 tmp = tmp * radix + c;
2560 break;
2561 default:
2562 goto out2;
2563 }
2564 }
2565 out2:
2566 if (tmp == 0.0)
2567 return SCM_BOOL_F; /* `slash zero' not allowed */
2568 if (i < len)
2569 while (str[i] == '#')
2570 { /* optional sharps */
2571 tmp *= radix;
2572 if (++i == len)
2573 break;
2574 }
2575 res /= tmp;
2576 goto done;
0f2d19dd 2577 }
f872b822
MD
2578
2579 if (str[i] == '.')
2580 { /* decimal point notation */
2581 if (radix != 10)
2582 return SCM_BOOL_F; /* must be radix 10 */
2583 while (++i < len)
2584 {
2585 switch (c = str[i])
2586 {
2587 case DIGITS:
2588 point--;
2589 res = res * 10.0 + c - '0';
2590 flg = 1;
2591 break;
2592 default:
2593 goto out3;
2594 }
2595 }
2596 out3:
2597 if (!flg)
2598 return SCM_BOOL_F; /* no digits before or after decimal point */
2599 if (i == len)
2600 goto adjust;
2601 while (str[i] == '#')
2602 { /* ignore remaining sharps */
2603 if (++i == len)
2604 goto adjust;
2605 }
0f2d19dd 2606 }
0f2d19dd 2607
f872b822
MD
2608 switch (str[i])
2609 { /* exponent */
2610 case 'd':
2611 case 'D':
2612 case 'e':
2613 case 'E':
2614 case 'f':
2615 case 'F':
2616 case 'l':
2617 case 'L':
2618 case 's':
2619 case 'S':
2620 {
2621 int expsgn = 1, expon = 0;
2622 if (radix != 10)
2623 return SCM_BOOL_F; /* only in radix 10 */
2624 if (++i == len)
2625 return SCM_BOOL_F; /* bad exponent */
2626 switch (str[i])
2627 {
2628 case '-':
2629 expsgn = (-1);
2630 case '+':
2631 if (++i == len)
2632 return SCM_BOOL_F; /* bad exponent */
2633 }
2634 if (str[i] < '0' || str[i] > '9')
2635 return SCM_BOOL_F; /* bad exponent */
2636 do
2637 {
2638 switch (c = str[i])
2639 {
2640 case DIGITS:
2641 expon = expon * 10 + c - '0';
f3ae5d60 2642 if (expon > SCM_MAXEXP)
f872b822
MD
2643 return SCM_BOOL_F; /* exponent too large */
2644 break;
2645 default:
2646 goto out4;
2647 }
2648 }
2649 while (++i < len);
2650 out4:
2651 point += expsgn * expon;
0f2d19dd 2652 }
f872b822 2653 }
0f2d19dd
JB
2654
2655 adjust:
2656 if (point >= 0)
f872b822
MD
2657 while (point--)
2658 res *= 10.0;
0f2d19dd 2659 else
f872b822
MD
2660#ifdef _UNICOS
2661 while (point++)
2662 res *= 0.1;
2663#else
2664 while (point++)
2665 res /= 10.0;
2666#endif
0f2d19dd
JB
2667
2668 done:
2669 /* at this point, we have a legitimate floating point result */
f872b822
MD
2670 if (lead_sgn == -1.0)
2671 res = -res;
2672 if (i == len)
f8de44c1 2673 return scm_make_real (res);
f872b822
MD
2674
2675 if (str[i] == 'i' || str[i] == 'I')
2676 { /* pure imaginary number */
2677 if (lead_sgn == 0.0)
2678 return SCM_BOOL_F; /* must have leading sign */
2679 if (++i < len)
2680 return SCM_BOOL_F; /* `i' not last character */
f8de44c1 2681 return scm_make_complex (0.0, res);
f872b822 2682 }
0f2d19dd 2683
f872b822
MD
2684 switch (str[i++])
2685 {
2686 case '-':
2687 lead_sgn = -1.0;
2688 break;
2689 case '+':
2690 lead_sgn = 1.0;
2691 break;
2692 case '@':
2693 { /* polar input for complex number */
2694 /* get a `real' for scm_angle */
2695 second = scm_istr2flo (&str[i], (long) (len - i), radix);
f3ae5d60 2696 if (!SCM_SLOPPY_INEXACTP (second))
f872b822 2697 return SCM_BOOL_F; /* not `real' */
f3ae5d60 2698 if (SCM_SLOPPY_COMPLEXP (second))
f872b822 2699 return SCM_BOOL_F; /* not `real' */
5986c47d 2700 tmp = SCM_REAL_VALUE (second);
f8de44c1 2701 return scm_make_complex (res * cos (tmp), res * sin (tmp));
f872b822
MD
2702 }
2703 default:
2704 return SCM_BOOL_F;
2705 }
0f2d19dd
JB
2706
2707 /* at this point, last char must be `i' */
f872b822
MD
2708 if (str[len - 1] != 'i' && str[len - 1] != 'I')
2709 return SCM_BOOL_F;
0f2d19dd 2710 /* handles `x+i' and `x-i' */
f872b822 2711 if (i == (len - 1))
f8de44c1 2712 return scm_make_complex (res, lead_sgn);
0f2d19dd 2713 /* get a `ureal' for complex part */
f872b822 2714 second = scm_istr2flo (&str[i], (long) ((len - i) - 1), radix);
f3ae5d60 2715 if (!SCM_INEXACTP (second))
f872b822 2716 return SCM_BOOL_F; /* not `ureal' */
f3ae5d60 2717 if (SCM_SLOPPY_COMPLEXP (second))
f872b822 2718 return SCM_BOOL_F; /* not `ureal' */
5986c47d 2719 tmp = SCM_REAL_VALUE (second);
f872b822
MD
2720 if (tmp < 0.0)
2721 return SCM_BOOL_F; /* not `ureal' */
f8de44c1 2722 return scm_make_complex (res, (lead_sgn * tmp));
0f2d19dd 2723}
0f2d19dd
JB
2724
2725
1cc91f1b 2726
0f2d19dd 2727SCM
1bbd0b84 2728scm_istring2number (char *str, long len, long radix)
0f2d19dd
JB
2729{
2730 int i = 0;
2731 char ex = 0;
2732 char ex_p = 0, rx_p = 0; /* Only allow 1 exactness and 1 radix prefix */
2733 SCM res;
f872b822
MD
2734 if (len == 1)
2735 if (*str == '+' || *str == '-') /* Catches lone `+' and `-' for speed */
0f2d19dd
JB
2736 return SCM_BOOL_F;
2737
f872b822
MD
2738 while ((len - i) >= 2 && str[i] == '#' && ++i)
2739 switch (str[i++])
2740 {
2741 case 'b':
2742 case 'B':
2743 if (rx_p++)
2744 return SCM_BOOL_F;
2745 radix = 2;
2746 break;
2747 case 'o':
2748 case 'O':
2749 if (rx_p++)
2750 return SCM_BOOL_F;
2751 radix = 8;
2752 break;
2753 case 'd':
2754 case 'D':
2755 if (rx_p++)
2756 return SCM_BOOL_F;
2757 radix = 10;
2758 break;
2759 case 'x':
2760 case 'X':
2761 if (rx_p++)
2762 return SCM_BOOL_F;
2763 radix = 16;
2764 break;
2765 case 'i':
2766 case 'I':
2767 if (ex_p++)
2768 return SCM_BOOL_F;
2769 ex = 2;
2770 break;
2771 case 'e':
2772 case 'E':
2773 if (ex_p++)
2774 return SCM_BOOL_F;
2775 ex = 1;
2776 break;
2777 default:
2778 return SCM_BOOL_F;
2779 }
2780
2781 switch (ex)
2782 {
2783 case 1:
2784 return scm_istr2int (&str[i], len - i, radix);
2785 case 0:
2786 res = scm_istr2int (&str[i], len - i, radix);
2787 if (SCM_NFALSEP (res))
2788 return res;
f872b822
MD
2789 case 2:
2790 return scm_istr2flo (&str[i], len - i, radix);
f872b822 2791 }
0f2d19dd
JB
2792 return SCM_BOOL_F;
2793}
2794
2795
a1ec6916 2796SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794
DH
2797 (SCM string, SCM radix),
2798 "Returns a number of the maximally precise representation\n"
2799 "expressed by the given STRING. RADIX must be an exact integer,\n"
2800 "either 2, 8, 10, or 16. If supplied, RADIX is a default radix\n"
2801 "that may be overridden by an explicit radix prefix in STRING\n"
2802 "(e.g. \"#o177\"). If RADIX is not supplied, then the default\n"
2803 "radix is 10. If string is not a syntactically valid notation\n"
2804 "for a number, then `string->number' returns #f. (r5rs)")
1bbd0b84 2805#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
2806{
2807 SCM answer;
1bbd0b84 2808 int base;
bb628794 2809 SCM_VALIDATE_ROSTRING (1,string);
3b3b36dd 2810 SCM_VALIDATE_INUM_MIN_DEF_COPY (2,radix,2,10,base);
bb628794
DH
2811 answer = scm_istring2number (SCM_ROCHARS (string),
2812 SCM_ROLENGTH (string),
1bbd0b84 2813 base);
bb628794 2814 return scm_return_first (answer, string);
0f2d19dd 2815}
1bbd0b84 2816#undef FUNC_NAME
0f2d19dd
JB
2817/*** END strs->nums ***/
2818
5986c47d 2819
0f2d19dd 2820SCM
f3ae5d60 2821scm_make_real (double x)
0f2d19dd
JB
2822{
2823 SCM z;
3a9809df
DH
2824 SCM_NEWCELL2 (z);
2825 SCM_SET_CELL_TYPE (z, scm_tc16_real);
2826 SCM_REAL_VALUE (z) = x;
0f2d19dd
JB
2827 return z;
2828}
0f2d19dd 2829
5986c47d 2830
f3ae5d60
MD
2831SCM
2832scm_make_complex (double x, double y)
2833{
3a9809df
DH
2834 if (y == 0.0) {
2835 return scm_make_real (x);
2836 } else {
2837 SCM z;
2838 SCM_NEWSMOB (z, scm_tc16_complex, scm_must_malloc (2L * sizeof (double), "complex"));
2839 SCM_COMPLEX_REAL (z) = x;
2840 SCM_COMPLEX_IMAG (z) = y;
2841 return z;
2842 }
f3ae5d60 2843}
1cc91f1b 2844
5986c47d 2845
0f2d19dd 2846SCM
1bbd0b84 2847scm_bigequal (SCM x, SCM y)
0f2d19dd
JB
2848{
2849#ifdef SCM_BIGDIG
f872b822
MD
2850 if (0 == scm_bigcomp (x, y))
2851 return SCM_BOOL_T;
0f2d19dd
JB
2852#endif
2853 return SCM_BOOL_F;
2854}
2855
0f2d19dd 2856SCM
f3ae5d60 2857scm_real_equalp (SCM x, SCM y)
0f2d19dd 2858{
f3ae5d60 2859 return SCM_BOOL (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0f2d19dd
JB
2860}
2861
f3ae5d60
MD
2862SCM
2863scm_complex_equalp (SCM x, SCM y)
2864{
2865 return SCM_BOOL (SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y)
2866 && SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y));
2867}
0f2d19dd
JB
2868
2869
2870
1bbd0b84 2871SCM_REGISTER_PROC (s_number_p, "number?", 1, 0, 0, scm_number_p);
1cc91f1b 2872
a1ec6916 2873SCM_DEFINE (scm_number_p, "complex?", 1, 0, 0,
1bbd0b84 2874 (SCM x),
bb628794
DH
2875 "Return #t if X is a complex number, #f else. Note that the\n"
2876 "sets of real, rational and integer values form subsets of the\n"
2877 "set of complex numbers, i. e. the predicate will also be\n"
2878 "fulfilled if X is a real, rational or integer number.")
1bbd0b84 2879#define FUNC_NAME s_scm_number_p
0f2d19dd 2880{
bb628794 2881 return SCM_BOOL (SCM_NUMBERP (x));
0f2d19dd 2882}
1bbd0b84 2883#undef FUNC_NAME
0f2d19dd
JB
2884
2885
1bbd0b84 2886SCM_REGISTER_PROC (s_real_p, "real?", 1, 0, 0, scm_real_p);
1cc91f1b 2887
a1ec6916 2888SCM_DEFINE (scm_real_p, "rational?", 1, 0, 0,
1bbd0b84 2889 (SCM x),
bb628794
DH
2890 "Return #t if X is a rational number, #f else. Note that the\n"
2891 "set of integer values forms a subset of the set of rational\n"
2892 "numbers, i. e. the predicate will also be fulfilled if X is an\n"
2893 "integer number.")
1bbd0b84 2894#define FUNC_NAME s_scm_real_p
0f2d19dd 2895{
bb628794 2896 if (SCM_INUMP (x)) {
0f2d19dd 2897 return SCM_BOOL_T;
bb628794 2898 } else if (SCM_IMP (x)) {
0f2d19dd 2899 return SCM_BOOL_F;
bb628794 2900 } else if (SCM_SLOPPY_REALP (x)) {
0f2d19dd 2901 return SCM_BOOL_T;
bb628794 2902 } else if (SCM_BIGP (x)) {
0f2d19dd 2903 return SCM_BOOL_T;
bb628794
DH
2904 } else {
2905 return SCM_BOOL_F;
2906 }
0f2d19dd 2907}
1bbd0b84 2908#undef FUNC_NAME
0f2d19dd
JB
2909
2910
a1ec6916 2911SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 2912 (SCM x),
bb628794 2913 "Return #t if X is an integer number, #f else.")
1bbd0b84 2914#define FUNC_NAME s_scm_integer_p
0f2d19dd
JB
2915{
2916 double r;
f872b822
MD
2917 if (SCM_INUMP (x))
2918 return SCM_BOOL_T;
2919 if (SCM_IMP (x))
2920 return SCM_BOOL_F;
f872b822
MD
2921 if (SCM_BIGP (x))
2922 return SCM_BOOL_T;
f3ae5d60 2923 if (!SCM_SLOPPY_INEXACTP (x))
f872b822 2924 return SCM_BOOL_F;
f3ae5d60 2925 if (SCM_SLOPPY_COMPLEXP (x))
f872b822 2926 return SCM_BOOL_F;
5986c47d 2927 r = SCM_REAL_VALUE (x);
f872b822
MD
2928 if (r == floor (r))
2929 return SCM_BOOL_T;
0f2d19dd
JB
2930 return SCM_BOOL_F;
2931}
1bbd0b84 2932#undef FUNC_NAME
0f2d19dd
JB
2933
2934
a1ec6916 2935SCM_DEFINE (scm_inexact_p, "inexact?", 1, 0, 0,
1bbd0b84 2936 (SCM x),
bb628794 2937 "Return #t if X is an inexact number, #f else.")
1bbd0b84 2938#define FUNC_NAME s_scm_inexact_p
0f2d19dd 2939{
f4c627b3 2940 return SCM_BOOL (SCM_INEXACTP (x));
0f2d19dd 2941}
1bbd0b84 2942#undef FUNC_NAME
0f2d19dd
JB
2943
2944
152f82bf 2945SCM_GPROC1 (s_eq_p, "=", scm_tc7_rpsubr, scm_num_eq_p, g_eq_p);
1cc91f1b 2946
0f2d19dd 2947SCM
6e8d25a6 2948scm_num_eq_p (SCM x, SCM y)
0f2d19dd 2949{
f4c627b3
DH
2950 if (SCM_INUMP (x)) {
2951 long xx = SCM_INUM (x);
2952 if (SCM_INUMP (y)) {
2953 long yy = SCM_INUM (y);
2954 return SCM_BOOL (xx == yy);
2955 } else if (SCM_BIGP (y)) {
2956 return SCM_BOOL_F;
2957 } else if (SCM_REALP (y)) {
2958 return SCM_BOOL ((double) xx == SCM_REAL_VALUE (y));
2959 } else if (SCM_COMPLEXP (y)) {
2960 return SCM_BOOL (((double) xx == SCM_COMPLEX_REAL (y))
2961 && (0.0 == SCM_COMPLEX_IMAG (y)));
2962 } else {
2963 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 2964 }
f4c627b3
DH
2965 } else if (SCM_BIGP (x)) {
2966 if (SCM_INUMP (y)) {
2967 return SCM_BOOL_F;
2968 } else if (SCM_BIGP (y)) {
2969 return SCM_BOOL (0 == scm_bigcomp (x, y));
2970 } else if (SCM_REALP (y)) {
2971 return SCM_BOOL (scm_big2dbl (x) == SCM_REAL_VALUE (y));
2972 } else if (SCM_COMPLEXP (y)) {
2973 return SCM_BOOL ((scm_big2dbl (x) == SCM_COMPLEX_REAL (y))
2974 && (0.0 == SCM_COMPLEX_IMAG (y)));
2975 } else {
2976 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
2977 }
2978 } else if (SCM_REALP (x)) {
2979 if (SCM_INUMP (y)) {
2980 return SCM_BOOL (SCM_REAL_VALUE (x) == (double) SCM_INUM (y));
2981 } else if (SCM_BIGP (y)) {
2982 return SCM_BOOL (SCM_REAL_VALUE (x) == scm_big2dbl (y));
2983 } else if (SCM_REALP (y)) {
2984 return SCM_BOOL (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
2985 } else if (SCM_COMPLEXP (y)) {
2986 return SCM_BOOL ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
2987 && (0.0 == SCM_COMPLEX_IMAG (y)));
2988 } else {
2989 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 2990 }
f4c627b3
DH
2991 } else if (SCM_COMPLEXP (x)) {
2992 if (SCM_INUMP (y)) {
2993 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == (double) SCM_INUM (y))
2994 && (SCM_COMPLEX_IMAG (x) == 0.0));
2995 } else if (SCM_BIGP (y)) {
2996 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == scm_big2dbl (y))
2997 && (SCM_COMPLEX_IMAG (x) == 0.0));
2998 } else if (SCM_REALP (y)) {
2999 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
3000 && (SCM_COMPLEX_IMAG (x) == 0.0));
3001 } else if (SCM_COMPLEXP (y)) {
3002 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
3003 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
3004 } else {
3005 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
3006 }
3007 } else {
3008 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARG1, s_eq_p);
3009 }
0f2d19dd
JB
3010}
3011
3012
152f82bf 3013SCM_GPROC1 (s_less_p, "<", scm_tc7_rpsubr, scm_less_p, g_less_p);
1cc91f1b 3014
0f2d19dd 3015SCM
6e8d25a6 3016scm_less_p (SCM x, SCM y)
0f2d19dd 3017{
f4c627b3
DH
3018 if (SCM_INUMP (x)) {
3019 long xx = SCM_INUM (x);
3020 if (SCM_INUMP (y)) {
3021 long yy = SCM_INUM (y);
3022 return SCM_BOOL (xx < yy);
3023 } else if (SCM_BIGP (y)) {
3024 return SCM_BOOL (!SCM_BIGSIGN (y));
3025 } else if (SCM_REALP (y)) {
3026 return SCM_BOOL ((double) xx < SCM_REAL_VALUE (y));
3027 } else {
3028 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3029 }
f4c627b3
DH
3030 } else if (SCM_BIGP (x)) {
3031 if (SCM_INUMP (y)) {
3032 return SCM_BOOL (SCM_BIGSIGN (x));
3033 } else if (SCM_BIGP (y)) {
3034 return SCM_BOOL (1 == scm_bigcomp (x, y));
3035 } else if (SCM_REALP (y)) {
3036 return SCM_BOOL (scm_big2dbl (x) < SCM_REAL_VALUE (y));
3037 } else {
3038 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
3039 }
3040 } else if (SCM_REALP (x)) {
3041 if (SCM_INUMP (y)) {
3042 return SCM_BOOL (SCM_REAL_VALUE (x) < (double) SCM_INUM (y));
3043 } else if (SCM_BIGP (y)) {
3044 return SCM_BOOL (SCM_REAL_VALUE (x) < scm_big2dbl (y));
3045 } else if (SCM_REALP (y)) {
3046 return SCM_BOOL (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
3047 } else {
3048 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3049 }
f4c627b3
DH
3050 } else {
3051 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARG1, s_less_p);
3052 }
0f2d19dd
JB
3053}
3054
3055
c3ee7520 3056SCM_DEFINE1 (scm_gr_p, ">", scm_tc7_rpsubr,
1bbd0b84 3057 (SCM x, SCM y),
bb628794
DH
3058 "Return #t if the list of parameters is monotonically\n"
3059 "increasing.")
1bbd0b84 3060#define FUNC_NAME s_scm_gr_p
0f2d19dd 3061{
f872b822 3062 return scm_less_p (y, x);
0f2d19dd 3063}
1bbd0b84 3064#undef FUNC_NAME
0f2d19dd
JB
3065
3066
c3ee7520 3067SCM_DEFINE1 (scm_leq_p, "<=", scm_tc7_rpsubr,
1bbd0b84 3068 (SCM x, SCM y),
bb628794
DH
3069 "Return #t if the list of parameters is monotonically\n"
3070 "non-decreasing.")
1bbd0b84 3071#define FUNC_NAME s_scm_leq_p
0f2d19dd 3072{
f872b822 3073 return SCM_BOOL_NOT (scm_less_p (y, x));
0f2d19dd 3074}
1bbd0b84 3075#undef FUNC_NAME
0f2d19dd
JB
3076
3077
c3ee7520 3078SCM_DEFINE1 (scm_geq_p, ">=", scm_tc7_rpsubr,
1bbd0b84 3079 (SCM x, SCM y),
bb628794
DH
3080 "Return #t if the list of parameters is monotonically\n"
3081 "non-increasing.")
1bbd0b84 3082#define FUNC_NAME s_scm_geq_p
0f2d19dd 3083{
f872b822 3084 return SCM_BOOL_NOT (scm_less_p (x, y));
0f2d19dd 3085}
1bbd0b84 3086#undef FUNC_NAME
0f2d19dd
JB
3087
3088
152f82bf 3089SCM_GPROC (s_zero_p, "zero?", 1, 0, 0, scm_zero_p, g_zero_p);
1cc91f1b 3090
0f2d19dd 3091SCM
6e8d25a6 3092scm_zero_p (SCM z)
0f2d19dd 3093{
c2ff8ab0
DH
3094 if (SCM_INUMP (z)) {
3095 return SCM_BOOL (SCM_EQ_P (z, SCM_INUM0));
3096 } else if (SCM_BIGP (z)) {
3097 return SCM_BOOL_F;
3098 } else if (SCM_REALP (z)) {
3099 return SCM_BOOL (SCM_REAL_VALUE (z) == 0.0);
3100 } else if (SCM_COMPLEXP (z)) {
3101 return SCM_BOOL (SCM_COMPLEX_REAL (z) == 0.0
3102 && SCM_COMPLEX_IMAG (z) == 0.0);
3103 } else {
3104 SCM_WTA_DISPATCH_1 (g_zero_p, z, SCM_ARG1, s_zero_p);
3105 }
0f2d19dd
JB
3106}
3107
3108
152f82bf 3109SCM_GPROC (s_positive_p, "positive?", 1, 0, 0, scm_positive_p, g_positive_p);
1cc91f1b 3110
0f2d19dd 3111SCM
6e8d25a6 3112scm_positive_p (SCM x)
0f2d19dd 3113{
c2ff8ab0
DH
3114 if (SCM_INUMP (x)) {
3115 return SCM_BOOL (SCM_INUM (x) > 0);
3116 } else if (SCM_BIGP (x)) {
3117 return SCM_BOOL (!SCM_BIGSIGN (x));
3118 } else if (SCM_REALP (x)) {
3119 return SCM_BOOL(SCM_REAL_VALUE (x) > 0.0);
3120 } else {
3121 SCM_WTA_DISPATCH_1 (g_positive_p, x, SCM_ARG1, s_positive_p);
3122 }
0f2d19dd
JB
3123}
3124
3125
152f82bf 3126SCM_GPROC (s_negative_p, "negative?", 1, 0, 0, scm_negative_p, g_negative_p);
1cc91f1b 3127
0f2d19dd 3128SCM
6e8d25a6 3129scm_negative_p (SCM x)
0f2d19dd 3130{
c2ff8ab0
DH
3131 if (SCM_INUMP (x)) {
3132 return SCM_BOOL (SCM_INUM (x) < 0);
3133 } else if (SCM_BIGP (x)) {
3134 return SCM_BOOL (SCM_BIGSIGN (x));
3135 } else if (SCM_REALP (x)) {
3136 return SCM_BOOL(SCM_REAL_VALUE (x) < 0.0);
3137 } else {
3138 SCM_WTA_DISPATCH_1 (g_negative_p, x, SCM_ARG1, s_negative_p);
3139 }
0f2d19dd
JB
3140}
3141
3142
9de33deb 3143SCM_GPROC1 (s_max, "max", scm_tc7_asubr, scm_max, g_max);
1cc91f1b 3144
0f2d19dd 3145SCM
6e8d25a6 3146scm_max (SCM x, SCM y)
0f2d19dd 3147{
f4c627b3
DH
3148 if (SCM_UNBNDP (y)) {
3149 if (SCM_UNBNDP (x)) {
3150 SCM_WTA_DISPATCH_0 (g_max, x, SCM_ARG1, s_max);
3151 } else if (SCM_NUMBERP (x)) {
f872b822 3152 return x;
f4c627b3
DH
3153 } else {
3154 SCM_WTA_DISPATCH_1 (g_max, x, SCM_ARG1, s_max);
f872b822 3155 }
f4c627b3
DH
3156 }
3157
3158 if (SCM_INUMP (x)) {
3159 long xx = SCM_INUM (x);
3160 if (SCM_INUMP (y)) {
3161 long yy = SCM_INUM (y);
3162 return (xx < yy) ? y : x;
3163 } else if (SCM_BIGP (y)) {
3164 return SCM_BIGSIGN (y) ? x : y;
3165 } else if (SCM_REALP (y)) {
3166 double z = xx;
3167 return (z <= SCM_REAL_VALUE (y)) ? y : scm_make_real (z);
3168 } else {
3169 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3170 }
f4c627b3
DH
3171 } else if (SCM_BIGP (x)) {
3172 if (SCM_INUMP (y)) {
3173 return SCM_BIGSIGN (x) ? y : x;
3174 } else if (SCM_BIGP (y)) {
3175 return (1 == scm_bigcomp (x, y)) ? y : x;
3176 } else if (SCM_REALP (y)) {
3177 double z = scm_big2dbl (x);
3178 return (z <= SCM_REAL_VALUE (y)) ? y : scm_make_real (z);
3179 } else {
3180 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
3181 }
3182 } else if (SCM_REALP (x)) {
3183 if (SCM_INUMP (y)) {
3184 double z = SCM_INUM (y);
3185 return (SCM_REAL_VALUE (x) < z) ? scm_make_real (z) : x;
3186 } else if (SCM_BIGP (y)) {
3187 double z = scm_big2dbl (y);
3188 return (SCM_REAL_VALUE (x) < z) ? scm_make_real (z) : x;
3189 } else if (SCM_REALP (y)) {
3190 return (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y)) ? y : x;
3191 } else {
3192 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3193 }
f4c627b3
DH
3194 } else {
3195 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARG1, s_max);
3196 }
0f2d19dd
JB
3197}
3198
3199
9de33deb 3200SCM_GPROC1 (s_min, "min", scm_tc7_asubr, scm_min, g_min);
1cc91f1b 3201
0f2d19dd 3202SCM
6e8d25a6 3203scm_min (SCM x, SCM y)
0f2d19dd 3204{
f4c627b3
DH
3205 if (SCM_UNBNDP (y)) {
3206 if (SCM_UNBNDP (x)) {
3207 SCM_WTA_DISPATCH_0 (g_min, x, SCM_ARG1, s_min);
3208 } else if (SCM_NUMBERP (x)) {
f872b822 3209 return x;
f4c627b3
DH
3210 } else {
3211 SCM_WTA_DISPATCH_1 (g_min, x, SCM_ARG1, s_min);
f872b822 3212 }
f4c627b3
DH
3213 }
3214
3215 if (SCM_INUMP (x)) {
3216 long xx = SCM_INUM (x);
3217 if (SCM_INUMP (y)) {
3218 long yy = SCM_INUM (y);
3219 return (xx < yy) ? x : y;
3220 } else if (SCM_BIGP (y)) {
3221 return SCM_BIGSIGN (y) ? y : x;
3222 } else if (SCM_REALP (y)) {
3223 double z = xx;
3224 return (z < SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
3225 } else {
3226 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3227 }
f4c627b3
DH
3228 } else if (SCM_BIGP (x)) {
3229 if (SCM_INUMP (y)) {
3230 return SCM_BIGSIGN (x) ? x : y;
3231 } else if (SCM_BIGP (y)) {
3232 return (-1 == scm_bigcomp (x, y)) ? y : x;
3233 } else if (SCM_REALP (y)) {
3234 double z = scm_big2dbl (x);
3235 return (z < SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
3236 } else {
3237 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
3238 }
3239 } else if (SCM_REALP (x)) {
3240 if (SCM_INUMP (y)) {
3241 double z = SCM_INUM (y);
3242 return (SCM_REAL_VALUE (x) <= z) ? x : scm_make_real (z);
3243 } else if (SCM_BIGP (y)) {
3244 double z = scm_big2dbl (y);
3245 return (SCM_REAL_VALUE (x) <= z) ? x : scm_make_real (z);
3246 } else if (SCM_REALP (y)) {
3247 return (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y)) ? x : y;
3248 } else {
3249 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3250 }
f4c627b3
DH
3251 } else {
3252 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
3253 }
0f2d19dd
JB
3254}
3255
3256
9de33deb 3257SCM_GPROC1 (s_sum, "+", scm_tc7_asubr, scm_sum, g_sum);
1cc91f1b 3258
0f2d19dd 3259SCM
6e8d25a6 3260scm_sum (SCM x, SCM y)
0f2d19dd 3261{
98cb6e75
DH
3262 if (SCM_UNBNDP (y)) {
3263 if (SCM_UNBNDP (x)) {
3264 return SCM_INUM0;
3265 } else if (SCM_NUMBERP (x)) {
f872b822 3266 return x;
98cb6e75
DH
3267 } else {
3268 SCM_WTA_DISPATCH_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 3269 }
98cb6e75 3270 }
c209c88e 3271
98cb6e75
DH
3272 if (SCM_INUMP (x)) {
3273 long int xx = SCM_INUM (x);
3274 if (SCM_INUMP (y)) {
3275 long int yy = SCM_INUM (y);
3276 long int z = xx + yy;
3277 if (SCM_FIXABLE (z)) {
3278 return SCM_MAKINUM (z);
3279 } else {
3280#ifdef SCM_BIGDIG
3281 return scm_long2big (z);
3282#else /* SCM_BIGDIG */
3283 return scm_make_real ((double) z);
3284#endif /* SCM_BIGDIG */
3285 }
3286 } else if (SCM_BIGP (y)) {
3287 intbig:
f872b822 3288 {
98cb6e75
DH
3289 long int xx = SCM_INUM (x);
3290#ifndef SCM_DIGSTOOBIG
3291 long z = scm_pseudolong (xx);
3292 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3293 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, 0);
3294#else /* SCM_DIGSTOOBIG */
3295 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3296 scm_longdigs (xx, zdigs);
3297 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3298 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, 0);
3299#endif /* SCM_DIGSTOOBIG */
0f2d19dd 3300 }
98cb6e75
DH
3301 } else if (SCM_REALP (y)) {
3302 return scm_make_real (xx + SCM_REAL_VALUE (y));
3303 } else if (SCM_COMPLEXP (y)) {
3304 return scm_make_complex (xx + SCM_COMPLEX_REAL (y),
3305 SCM_COMPLEX_IMAG (y));
3306 } else {
3307 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 3308 }
98cb6e75
DH
3309 } else if (SCM_BIGP (x)) {
3310 if (SCM_INUMP (y)) {
3311 SCM_SWAP (x, y);
3312 goto intbig;
3313 } else if (SCM_BIGP (y)) {
3314 if (SCM_NUMDIGS (x) > SCM_NUMDIGS (y)) {
3315 SCM_SWAP (x, y);
3316 }
3317 return scm_addbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3318 SCM_BIGSIGN (x), y, 0);
3319 } else if (SCM_REALP (y)) {
3320 return scm_make_real (scm_big2dbl (x) + SCM_REAL_VALUE (y));
3321 } else if (SCM_COMPLEXP (y)) {
3322 return scm_make_complex (scm_big2dbl (x) + SCM_COMPLEX_REAL (y),
3323 SCM_COMPLEX_IMAG (y));
3324 } else {
3325 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 3326 }
98cb6e75
DH
3327 } else if (SCM_REALP (x)) {
3328 if (SCM_INUMP (y)) {
3329 return scm_make_real (SCM_REAL_VALUE (x) + SCM_INUM (y));
3330 } else if (SCM_BIGP (y)) {
3331 return scm_make_real (SCM_REAL_VALUE (x) + scm_big2dbl (y));
3332 } else if (SCM_REALP (y)) {
3333 return scm_make_real (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
3334 } else if (SCM_COMPLEXP (y)) {
3335 return scm_make_complex (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
3336 SCM_COMPLEX_IMAG (y));
3337 } else {
3338 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
3339 }
3340 } else if (SCM_COMPLEXP (x)) {
3341 if (SCM_INUMP (y)) {
3342 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_INUM (y),
3343 SCM_COMPLEX_IMAG (x));
3344 } else if (SCM_BIGP (y)) {
3345 return scm_make_complex (SCM_COMPLEX_REAL (x) + scm_big2dbl (y),
3346 SCM_COMPLEX_IMAG (x));
3347 } else if (SCM_REALP (y)) {
3348 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
3349 SCM_COMPLEX_IMAG (x));
3350 } else if (SCM_COMPLEXP (y)) {
3351 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
3352 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
3353 } else {
3354 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
3355 }
3356 } else {
3357 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARG1, s_sum);
3358 }
0f2d19dd
JB
3359}
3360
3361
9de33deb 3362SCM_GPROC1 (s_difference, "-", scm_tc7_asubr, scm_difference, g_difference);
1cc91f1b 3363
0f2d19dd 3364SCM
6e8d25a6 3365scm_difference (SCM x, SCM y)
0f2d19dd 3366{
98cb6e75
DH
3367 if (SCM_UNBNDP (y)) {
3368 if (SCM_INUMP (x)) {
3369 long xx = -SCM_INUM (x);
3370 if (SCM_FIXABLE (xx)) {
3371 return SCM_MAKINUM (xx);
3372 } else {
f872b822 3373#ifdef SCM_BIGDIG
98cb6e75 3374 return scm_long2big (xx);
f3ae5d60 3375#else
98cb6e75 3376 return scm_make_real ((double) xx);
f3ae5d60 3377#endif
f3ae5d60 3378 }
98cb6e75
DH
3379 } else if (SCM_BIGP (x)) {
3380 SCM z = scm_copybig (x, !SCM_BIGSIGN (x));
3381 unsigned int digs = SCM_NUMDIGS (z);
3382 unsigned int size = digs * SCM_BITSPERDIG / SCM_CHAR_BIT;
3383 return size <= sizeof (SCM) ? scm_big2inum (z, digs) : z;
3384 } else if (SCM_REALP (x)) {
3385 return scm_make_real (-SCM_REAL_VALUE (x));
3386 } else if (SCM_COMPLEXP (x)) {
3387 return scm_make_complex (-SCM_COMPLEX_REAL (x), -SCM_COMPLEX_IMAG (x));
3388 } else {
3389 SCM_WTA_DISPATCH_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 3390 }
98cb6e75
DH
3391 }
3392
3393 if (SCM_INUMP (x)) {
3394 long int xx = SCM_INUM (x);
3395 if (SCM_INUMP (y)) {
3396 long int yy = SCM_INUM (y);
3397 long int z = xx - yy;
3398 if (SCM_FIXABLE (z)) {
3399 return SCM_MAKINUM (z);
3400 } else {
f872b822 3401#ifdef SCM_BIGDIG
98cb6e75 3402 return scm_long2big (z);
f872b822 3403#else
98cb6e75 3404 return scm_make_real ((double) z);
f872b822 3405#endif
98cb6e75
DH
3406 }
3407 } else if (SCM_BIGP (y)) {
3408#ifndef SCM_DIGSTOOBIG
3409 long z = scm_pseudolong (xx);
3410 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3411 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, SCM_BIGSIGNFLAG);
f872b822 3412#else
98cb6e75
DH
3413 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3414 scm_longdigs (xx, zdigs);
3415 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3416 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, SCM_BIGSIGNFLAG);
f872b822 3417#endif
98cb6e75
DH
3418 } else if (SCM_REALP (y)) {
3419 return scm_make_real (xx - SCM_REAL_VALUE (y));
3420 } else if (SCM_COMPLEXP (y)) {
3421 return scm_make_complex (xx - SCM_COMPLEX_REAL (y),
3422 -SCM_COMPLEX_IMAG (y));
3423 } else {
3424 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 3425 }
98cb6e75
DH
3426 } else if (SCM_BIGP (x)) {
3427 if (SCM_INUMP (y)) {
3428 long int yy = SCM_INUM (y);
3429#ifndef SCM_DIGSTOOBIG
3430 long z = scm_pseudolong (yy);
3431 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3432 (yy < 0) ? 0 : SCM_BIGSIGNFLAG, x, 0);
f872b822 3433#else
98cb6e75
DH
3434 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3435 scm_longdigs (yy, zdigs);
3436 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3437 (yy < 0) ? 0 : SCM_BIGSIGNFLAG, x, 0);
0f2d19dd 3438#endif
98cb6e75
DH
3439 } else if (SCM_BIGP (y)) {
3440 return (SCM_NUMDIGS (x) < SCM_NUMDIGS (y))
3441 ? scm_addbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3442 SCM_BIGSIGN (x), y, SCM_BIGSIGNFLAG)
3443 : scm_addbig (SCM_BDIGITS (y), SCM_NUMDIGS (y),
3444 SCM_BIGSIGN (y) ^ SCM_BIGSIGNFLAG, x, 0);
3445 } else if (SCM_REALP (y)) {
3446 return scm_make_real (scm_big2dbl (x) - SCM_REAL_VALUE (y));
3447 } else if (SCM_COMPLEXP (y)) {
3448 return scm_make_complex (scm_big2dbl (x) - SCM_COMPLEX_REAL (y),
3449 - SCM_COMPLEX_IMAG (y));
3450 } else {
3451 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
3452 }
3453 } else if (SCM_REALP (x)) {
3454 if (SCM_INUMP (y)) {
3455 return scm_make_real (SCM_REAL_VALUE (x) - SCM_INUM (y));
3456 } else if (SCM_BIGP (y)) {
3457 return scm_make_real (SCM_REAL_VALUE (x) - scm_big2dbl (y));
3458 } else if (SCM_REALP (y)) {
3459 return scm_make_real (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
3460 } else if (SCM_COMPLEXP (y)) {
3461 return scm_make_complex (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
3462 -SCM_COMPLEX_IMAG (y));
3463 } else {
3464 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
3465 }
3466 } else if (SCM_COMPLEXP (x)) {
3467 if (SCM_INUMP (y)) {
3468 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_INUM (y),
3469 SCM_COMPLEX_IMAG (x));
3470 } else if (SCM_BIGP (y)) {
3471 return scm_make_complex (SCM_COMPLEX_REAL (x) - scm_big2dbl (y),
3472 SCM_COMPLEX_IMAG (x));
3473 } else if (SCM_REALP (y)) {
3474 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
3475 SCM_COMPLEX_IMAG (x));
3476 } else if (SCM_COMPLEXP (y)) {
3477 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
3478 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
3479 } else {
3480 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
3481 }
3482 } else {
3483 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARG1, s_difference);
3484 }
0f2d19dd
JB
3485}
3486
3487
9de33deb 3488SCM_GPROC1 (s_product, "*", scm_tc7_asubr, scm_product, g_product);
1cc91f1b 3489
0f2d19dd 3490SCM
6e8d25a6 3491scm_product (SCM x, SCM y)
0f2d19dd 3492{
f4c627b3
DH
3493 if (SCM_UNBNDP (y)) {
3494 if (SCM_UNBNDP (x)) {
3495 return SCM_MAKINUM (1L);
3496 } else if (SCM_NUMBERP (x)) {
f872b822 3497 return x;
f4c627b3
DH
3498 } else {
3499 SCM_WTA_DISPATCH_1 (g_product, x, SCM_ARG1, s_product);
f872b822 3500 }
f4c627b3
DH
3501 }
3502
3503 if (SCM_INUMP (x)) {
3504 long xx;
3505
3506 intbig:
3507 xx = SCM_INUM (x);
3508
3509 if (xx == 0) {
f872b822 3510 return x;
f4c627b3
DH
3511 } else if (xx == 1) {
3512 return y;
3513 }
3514
3515 if (SCM_INUMP (y)) {
3516 long yy = SCM_INUM (y);
3517 long kk = xx * yy;
3518 SCM k = SCM_MAKINUM (kk);
3519 if (kk != SCM_INUM (k) || kk / xx != yy) {
f872b822 3520#ifdef SCM_BIGDIG
f4c627b3 3521 int sgn = (xx < 0) ^ (yy < 0);
f872b822 3522#ifndef SCM_DIGSTOOBIG
f4c627b3
DH
3523 long i = scm_pseudolong (xx);
3524 long j = scm_pseudolong (yy);
f872b822
MD
3525 return scm_mulbig ((SCM_BIGDIG *) & i, SCM_DIGSPERLONG,
3526 (SCM_BIGDIG *) & j, SCM_DIGSPERLONG, sgn);
3527#else /* SCM_DIGSTOOBIG */
f4c627b3
DH
3528 SCM_BIGDIG xdigs [SCM_DIGSPERLONG];
3529 SCM_BIGDIG ydigs [SCM_DIGSPERLONG];
3530 scm_longdigs (xx, xdigs);
3531 scm_longdigs (yy, ydigs);
3532 return scm_mulbig (xdigs, SCM_DIGSPERLONG,
3533 ydigs, SCM_DIGSPERLONG,
f872b822
MD
3534 sgn);
3535#endif
f4c627b3
DH
3536#else
3537 return scm_make_real (((double) xx) * ((double) yy));
3538#endif
3539 } else {
3540 return k;
0f2d19dd 3541 }
f4c627b3
DH
3542 } else if (SCM_BIGP (y)) {
3543#ifndef SCM_DIGSTOOBIG
3544 long z = scm_pseudolong (xx);
3545 return scm_mulbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3546 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3547 SCM_BIGSIGN (y) ? (xx > 0) : (xx < 0));
0f2d19dd 3548#else
f4c627b3
DH
3549 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3550 scm_longdigs (xx, zdigs);
3551 return scm_mulbig (zdigs, SCM_DIGSPERLONG,
3552 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3553 SCM_BIGSIGN (y) ? (xx > 0) : (xx < 0));
0f2d19dd 3554#endif
f4c627b3
DH
3555 } else if (SCM_REALP (y)) {
3556 return scm_make_real (xx * SCM_REAL_VALUE (y));
3557 } else if (SCM_COMPLEXP (y)) {
3558 return scm_make_complex (xx * SCM_COMPLEX_REAL (y),
3559 xx * SCM_COMPLEX_IMAG (y));
3560 } else {
3561 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3562 }
3563 } else if (SCM_BIGP (x)) {
3564 if (SCM_INUMP (y)) {
3565 SCM_SWAP (x, y);
3566 goto intbig;
3567 } else if (SCM_BIGP (y)) {
3568 return scm_mulbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3569 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3570 SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y));
3571 } else if (SCM_REALP (y)) {
3572 return scm_make_real (scm_big2dbl (x) * SCM_REAL_VALUE (y));
3573 } else if (SCM_COMPLEXP (y)) {
3574 double z = scm_big2dbl (x);
3575 return scm_make_complex (z * SCM_COMPLEX_REAL (y),
3576 z * SCM_COMPLEX_IMAG (y));
3577 } else {
3578 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3579 }
3580 } else if (SCM_REALP (x)) {
3581 if (SCM_INUMP (y)) {
3582 return scm_make_real (SCM_INUM (y) * SCM_REAL_VALUE (x));
3583 } else if (SCM_BIGP (y)) {
3584 return scm_make_real (scm_big2dbl (y) * SCM_REAL_VALUE (x));
3585 } else if (SCM_REALP (y)) {
3586 return scm_make_real (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
3587 } else if (SCM_COMPLEXP (y)) {
3588 return scm_make_complex (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
3589 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
3590 } else {
3591 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3592 }
3593 } else if (SCM_COMPLEXP (x)) {
3594 if (SCM_INUMP (y)) {
3595 return scm_make_complex (SCM_INUM (y) * SCM_COMPLEX_REAL (x),
3596 SCM_INUM (y) * SCM_COMPLEX_IMAG (x));
3597 } else if (SCM_BIGP (y)) {
3598 double z = scm_big2dbl (y);
3599 return scm_make_complex (z * SCM_COMPLEX_REAL (x),
3600 z * SCM_COMPLEX_IMAG (x));
3601 } else if (SCM_REALP (y)) {
3602 return scm_make_complex (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
3603 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
3604 } else if (SCM_COMPLEXP (y)) {
3605 return scm_make_complex (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
3606 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
3607 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
3608 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
3609 } else {
3610 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3611 }
3612 } else {
3613 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
3614 }
3615}
3616
3617
0f2d19dd 3618double
6e8d25a6 3619scm_num2dbl (SCM a, const char *why)
f4c627b3 3620#define FUNC_NAME why
0f2d19dd 3621{
f4c627b3 3622 if (SCM_INUMP (a)) {
0f2d19dd 3623 return (double) SCM_INUM (a);
f4c627b3
DH
3624 } else if (SCM_BIGP (a)) {
3625 return scm_big2dbl (a);
3626 } else if (SCM_REALP (a)) {
3627 return (SCM_REAL_VALUE (a));
3628 } else {
3629 SCM_WRONG_TYPE_ARG (SCM_ARGn, a);
3630 }
0f2d19dd 3631}
f4c627b3 3632#undef FUNC_NAME
0f2d19dd
JB
3633
3634
9de33deb 3635SCM_GPROC1 (s_divide, "/", scm_tc7_asubr, scm_divide, g_divide);
1cc91f1b 3636
0f2d19dd 3637SCM
6e8d25a6 3638scm_divide (SCM x, SCM y)
0f2d19dd 3639{
f8de44c1
DH
3640 double a;
3641
3642 if (SCM_UNBNDP (y)) {
3643 if (SCM_UNBNDP (x)) {
3644 SCM_WTA_DISPATCH_0 (g_divide, x, SCM_ARG1, s_divide);
3645 } else if (SCM_INUMP (x)) {
3646 if (SCM_EQ_P (x, SCM_MAKINUM (1L)) || SCM_EQ_P (x, SCM_MAKINUM (-1L))) {
3647 return x;
3648 } else {
3649 return scm_make_real (1.0 / (double) SCM_INUM (x));
3650 }
f8de44c1
DH
3651 } else if (SCM_BIGP (x)) {
3652 return scm_make_real (1.0 / scm_big2dbl (x));
f8de44c1
DH
3653 } else if (SCM_REALP (x)) {
3654 return scm_make_real (1.0 / SCM_REAL_VALUE (x));
3655 } else if (SCM_COMPLEXP (x)) {
3656 double r = SCM_COMPLEX_REAL (x);
3657 double i = SCM_COMPLEX_IMAG (x);
3658 double d = r * r + i * i;
3659 return scm_make_complex (r / d, -i / d);
3660 } else {
3661 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
3662 }
3663 }
3664
3665 if (SCM_INUMP (x)) {
3666 long xx = SCM_INUM (x);
3667 if (SCM_INUMP (y)) {
3668 long yy = SCM_INUM (y);
3669 if (yy == 0) {
f4c627b3 3670 scm_num_overflow (s_divide);
f8de44c1
DH
3671 } else if (xx % yy != 0) {
3672 return scm_make_real ((double) xx / (double) yy);
3673 } else {
3674 long z = xx / yy;
3675 if (SCM_FIXABLE (z)) {
3676 return SCM_MAKINUM (z);
3677 } else {
f872b822 3678#ifdef SCM_BIGDIG
f8de44c1 3679 return scm_long2big (z);
f872b822 3680#else
f8de44c1 3681 return scm_make_real ((double) xx / (double) yy);
f872b822 3682#endif
f872b822 3683 }
f8de44c1 3684 }
f8de44c1
DH
3685 } else if (SCM_BIGP (y)) {
3686 return scm_make_real ((double) xx / scm_big2dbl (y));
f8de44c1
DH
3687 } else if (SCM_REALP (y)) {
3688 return scm_make_real ((double) xx / SCM_REAL_VALUE (y));
3689 } else if (SCM_COMPLEXP (y)) {
3690 a = xx;
3691 complex_div: /* y _must_ be a complex number */
3692 {
3693 double r = SCM_COMPLEX_REAL (y);
3694 double i = SCM_COMPLEX_IMAG (y);
3695 double d = r * r + i * i;
3696 return scm_make_complex ((a * r) / d, (-a * i) / d);
3697 }
3698 } else {
3699 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
3700 }
f8de44c1
DH
3701 } else if (SCM_BIGP (x)) {
3702 if (SCM_INUMP (y)) {
3703 long int yy = SCM_INUM (y);
3704 if (yy == 0) {
3705 scm_num_overflow (s_divide);
3706 } else if (yy == 1) {
3707 return x;
3708 } else {
3709 long z = yy < 0 ? -yy : yy;
3710 if (z < SCM_BIGRAD) {
3711 SCM w = scm_copybig (x, SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0));
3712 return scm_divbigdig (SCM_BDIGITS (w), SCM_NUMDIGS (w),
3713 (SCM_BIGDIG) z)
3714 ? scm_make_real (scm_big2dbl (x) / (double) yy)
3715 : scm_normbig (w);
3716 } else {
3717 SCM w;
3718#ifndef SCM_DIGSTOOBIG
3719 z = scm_pseudolong (z);
3720 w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3721 (SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3722 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 3);
f872b822 3723#else
f8de44c1
DH
3724 SCM_BIGDIG zdigs[SCM_DIGSPERLONG];
3725 scm_longdigs (z, zdigs);
3726 w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3727 zdigs, SCM_DIGSPERLONG,
3728 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 3);
f872b822 3729#endif
f4c627b3
DH
3730 return (!SCM_UNBNDP (w))
3731 ? w
3732 : scm_make_real (scm_big2dbl (x) / (double) yy);
f872b822 3733 }
f8de44c1
DH
3734 }
3735 } else if (SCM_BIGP (y)) {
3736 SCM w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3737 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3738 SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y), 3);
f4c627b3
DH
3739 return (!SCM_UNBNDP (w))
3740 ? w
3741 : scm_make_real (scm_big2dbl (x) / scm_big2dbl (y));
f8de44c1
DH
3742 } else if (SCM_REALP (y)) {
3743 return scm_make_real (scm_big2dbl (x) / SCM_REAL_VALUE (y));
3744 } else if (SCM_COMPLEXP (y)) {
3745 a = scm_big2dbl (x);
3746 goto complex_div;
3747 } else {
3748 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 3749 }
f8de44c1
DH
3750 } else if (SCM_REALP (x)) {
3751 double rx = SCM_REAL_VALUE (x);
3752 if (SCM_INUMP (y)) {
3753 return scm_make_real (rx / (double) SCM_INUM (y));
f8de44c1
DH
3754 } else if (SCM_BIGP (y)) {
3755 return scm_make_real (rx / scm_big2dbl (y));
f8de44c1
DH
3756 } else if (SCM_REALP (y)) {
3757 return scm_make_real (rx / SCM_REAL_VALUE (y));
3758 } else if (SCM_COMPLEXP (y)) {
3759 a = rx;
3760 goto complex_div;
3761 } else {
3762 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 3763 }
f8de44c1
DH
3764 } else if (SCM_COMPLEXP (x)) {
3765 double rx = SCM_COMPLEX_REAL (x);
3766 double ix = SCM_COMPLEX_IMAG (x);
3767 if (SCM_INUMP (y)) {
3768 double d = SCM_INUM (y);
3769 return scm_make_complex (rx / d, ix / d);
f8de44c1
DH
3770 } else if (SCM_BIGP (y)) {
3771 double d = scm_big2dbl (y);
3772 return scm_make_complex (rx / d, ix / d);
f8de44c1
DH
3773 } else if (SCM_REALP (y)) {
3774 double d = SCM_REAL_VALUE (y);
3775 return scm_make_complex (rx / d, ix / d);
3776 } else if (SCM_COMPLEXP (y)) {
3777 double ry = SCM_COMPLEX_REAL (y);
3778 double iy = SCM_COMPLEX_IMAG (y);
3779 double d = ry * ry + iy * iy;
3780 return scm_make_complex ((rx * ry + ix * iy) / d,
3781 (ix * ry - rx * iy) / d);
3782 } else {
3783 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
3784 }
3785 } else {
3786 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd
JB
3787 }
3788}
3789
3790
9de33deb 3791SCM_GPROC1 (s_asinh, "$asinh", scm_tc7_cxr, (SCM (*)()) scm_asinh, g_asinh);
1cc91f1b 3792
0f2d19dd 3793double
6e8d25a6 3794scm_asinh (double x)
0f2d19dd 3795{
f872b822 3796 return log (x + sqrt (x * x + 1));
0f2d19dd
JB
3797}
3798
3799
3800
3801
9de33deb 3802SCM_GPROC1 (s_acosh, "$acosh", scm_tc7_cxr, (SCM (*)()) scm_acosh, g_acosh);
1cc91f1b 3803
0f2d19dd 3804double
6e8d25a6 3805scm_acosh (double x)
0f2d19dd 3806{
f872b822 3807 return log (x + sqrt (x * x - 1));
0f2d19dd
JB
3808}
3809
3810
3811
3812
9de33deb 3813SCM_GPROC1 (s_atanh, "$atanh", scm_tc7_cxr, (SCM (*)()) scm_atanh, g_atanh);
1cc91f1b 3814
0f2d19dd 3815double
6e8d25a6 3816scm_atanh (double x)
0f2d19dd 3817{
f872b822 3818 return 0.5 * log ((1 + x) / (1 - x));
0f2d19dd
JB
3819}
3820
3821
3822
3823
9de33deb 3824SCM_GPROC1 (s_truncate, "truncate", scm_tc7_cxr, (SCM (*)()) scm_truncate, g_truncate);
1cc91f1b 3825
0f2d19dd 3826double
6e8d25a6 3827scm_truncate (double x)
0f2d19dd 3828{
f872b822
MD
3829 if (x < 0.0)
3830 return -floor (-x);
3831 return floor (x);
0f2d19dd
JB
3832}
3833
3834
3835
9de33deb 3836SCM_GPROC1 (s_round, "round", scm_tc7_cxr, (SCM (*)()) scm_round, g_round);
1cc91f1b 3837
0f2d19dd 3838double
6e8d25a6 3839scm_round (double x)
0f2d19dd
JB
3840{
3841 double plus_half = x + 0.5;
f872b822 3842 double result = floor (plus_half);
0f2d19dd 3843 /* Adjust so that the scm_round is towards even. */
f872b822 3844 return (plus_half == result && plus_half / 2 != floor (plus_half / 2))
0f2d19dd
JB
3845 ? result - 1 : result;
3846}
3847
3848
3849
9de33deb 3850SCM_GPROC1 (s_exact_to_inexact, "exact->inexact", scm_tc7_cxr, (SCM (*)()) scm_exact_to_inexact, g_exact_to_inexact);
1cc91f1b 3851
0f2d19dd 3852double
6e8d25a6 3853scm_exact_to_inexact (double z)
0f2d19dd
JB
3854{
3855 return z;
3856}
3857
3858
9de33deb
MD
3859SCM_GPROC1 (s_i_floor, "floor", scm_tc7_cxr, (SCM (*)()) floor, g_i_floor);
3860SCM_GPROC1 (s_i_ceil, "ceiling", scm_tc7_cxr, (SCM (*)()) ceil, g_i_ceil);
3861SCM_GPROC1 (s_i_sqrt, "$sqrt", scm_tc7_cxr, (SCM (*)()) sqrt, g_i_sqrt);
3862SCM_GPROC1 (s_i_abs, "$abs", scm_tc7_cxr, (SCM (*)()) fabs, g_i_abs);
3863SCM_GPROC1 (s_i_exp, "$exp", scm_tc7_cxr, (SCM (*)()) exp, g_i_exp);
3864SCM_GPROC1 (s_i_log, "$log", scm_tc7_cxr, (SCM (*)()) log, g_i_log);
3865SCM_GPROC1 (s_i_sin, "$sin", scm_tc7_cxr, (SCM (*)()) sin, g_i_sin);
3866SCM_GPROC1 (s_i_cos, "$cos", scm_tc7_cxr, (SCM (*)()) cos, g_i_cos);
3867SCM_GPROC1 (s_i_tan, "$tan", scm_tc7_cxr, (SCM (*)()) tan, g_i_tan);
3868SCM_GPROC1 (s_i_asin, "$asin", scm_tc7_cxr, (SCM (*)()) asin, g_i_asin);
3869SCM_GPROC1 (s_i_acos, "$acos", scm_tc7_cxr, (SCM (*)()) acos, g_i_acos);
3870SCM_GPROC1 (s_i_atan, "$atan", scm_tc7_cxr, (SCM (*)()) atan, g_i_atan);
3871SCM_GPROC1 (s_i_sinh, "$sinh", scm_tc7_cxr, (SCM (*)()) sinh, g_i_sinh);
3872SCM_GPROC1 (s_i_cosh, "$cosh", scm_tc7_cxr, (SCM (*)()) cosh, g_i_cosh);
3873SCM_GPROC1 (s_i_tanh, "$tanh", scm_tc7_cxr, (SCM (*)()) tanh, g_i_tanh);
f872b822
MD
3874
3875struct dpair
3876{
3877 double x, y;
3878};
3879
3eeba8d4
JB
3880static void scm_two_doubles (SCM z1,
3881 SCM z2,
3882 const char *sstring,
3883 struct dpair * xy);
f872b822
MD
3884
3885static void
6e8d25a6 3886scm_two_doubles (SCM z1, SCM z2, const char *sstring, struct dpair *xy)
0f2d19dd 3887{
98cb6e75 3888 if (SCM_INUMP (z1)) {
f872b822 3889 xy->x = SCM_INUM (z1);
98cb6e75
DH
3890 } else if (SCM_BIGP (z1)) {
3891 xy->x = scm_big2dbl (z1);
3892 } else if (SCM_REALP (z1)) {
3893 xy->x = SCM_REAL_VALUE (z1);
3894 } else {
3895 scm_wrong_type_arg (sstring, SCM_ARG1, z1);
3896 }
3897
3898 if (SCM_INUMP (z2)) {
f872b822 3899 xy->y = SCM_INUM (z2);
98cb6e75
DH
3900 } else if (SCM_BIGP (z2)) {
3901 xy->y = scm_big2dbl (z2);
3902 } else if (SCM_REALP (z2)) {
3903 xy->y = SCM_REAL_VALUE (z2);
3904 } else {
3905 scm_wrong_type_arg (sstring, SCM_ARG2, z2);
3906 }
0f2d19dd
JB
3907}
3908
3909
a1ec6916 3910SCM_DEFINE (scm_sys_expt, "$expt", 2, 0, 0,
1bbd0b84 3911 (SCM z1, SCM z2),
bb628794 3912 "")
1bbd0b84 3913#define FUNC_NAME s_scm_sys_expt
0f2d19dd
JB
3914{
3915 struct dpair xy;
1bbd0b84 3916 scm_two_doubles (z1, z2, FUNC_NAME, &xy);
f8de44c1 3917 return scm_make_real (pow (xy.x, xy.y));
0f2d19dd 3918}
1bbd0b84 3919#undef FUNC_NAME
0f2d19dd
JB
3920
3921
a1ec6916 3922SCM_DEFINE (scm_sys_atan2, "$atan2", 2, 0, 0,
1bbd0b84 3923 (SCM z1, SCM z2),
b380b885 3924 "")
1bbd0b84 3925#define FUNC_NAME s_scm_sys_atan2
0f2d19dd
JB
3926{
3927 struct dpair xy;
1bbd0b84 3928 scm_two_doubles (z1, z2, FUNC_NAME, &xy);
f8de44c1 3929 return scm_make_real (atan2 (xy.x, xy.y));
0f2d19dd 3930}
1bbd0b84 3931#undef FUNC_NAME
0f2d19dd
JB
3932
3933
a1ec6916 3934SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
bb628794
DH
3935 (SCM real, SCM imaginary),
3936 "Return a complex number constructed of the given REAL and\n"
3937 "IMAGINARY parts.")
1bbd0b84 3938#define FUNC_NAME s_scm_make_rectangular
0f2d19dd
JB
3939{
3940 struct dpair xy;
bb628794 3941 scm_two_doubles (real, imaginary, FUNC_NAME, &xy);
f8de44c1 3942 return scm_make_complex (xy.x, xy.y);
0f2d19dd 3943}
1bbd0b84 3944#undef FUNC_NAME
0f2d19dd
JB
3945
3946
3947
a1ec6916 3948SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
1bbd0b84 3949 (SCM z1, SCM z2),
bb628794 3950 "Return the complex number Z1 * e^(i * Z2).")
1bbd0b84 3951#define FUNC_NAME s_scm_make_polar
0f2d19dd
JB
3952{
3953 struct dpair xy;
1bbd0b84 3954 scm_two_doubles (z1, z2, FUNC_NAME, &xy);
f8de44c1 3955 return scm_make_complex (xy.x * cos (xy.y), xy.x * sin (xy.y));
0f2d19dd 3956}
1bbd0b84 3957#undef FUNC_NAME
0f2d19dd
JB
3958
3959
152f82bf 3960SCM_GPROC (s_real_part, "real-part", 1, 0, 0, scm_real_part, g_real_part);
1cc91f1b 3961
0f2d19dd 3962SCM
6e8d25a6 3963scm_real_part (SCM z)
0f2d19dd 3964{
c2ff8ab0
DH
3965 if (SCM_INUMP (z)) {
3966 return z;
3967 } else if (SCM_BIGP (z)) {
3968 return z;
3969 } else if (SCM_REALP (z)) {
3970 return z;
3971 } else if (SCM_COMPLEXP (z)) {
3972 return scm_make_real (SCM_COMPLEX_REAL (z));
3973 } else {
3974 SCM_WTA_DISPATCH_1 (g_real_part, z, SCM_ARG1, s_real_part);
3975 }
0f2d19dd
JB
3976}
3977
3978
152f82bf 3979SCM_GPROC (s_imag_part, "imag-part", 1, 0, 0, scm_imag_part, g_imag_part);
1cc91f1b 3980
0f2d19dd 3981SCM
6e8d25a6 3982scm_imag_part (SCM z)
0f2d19dd 3983{
c2ff8ab0 3984 if (SCM_INUMP (z)) {
f872b822 3985 return SCM_INUM0;
c2ff8ab0 3986 } else if (SCM_BIGP (z)) {
f872b822 3987 return SCM_INUM0;
c2ff8ab0
DH
3988 } else if (SCM_REALP (z)) {
3989 return scm_flo0;
3990 } else if (SCM_COMPLEXP (z)) {
3991 return scm_make_real (SCM_COMPLEX_IMAG (z));
3992 } else {
3993 SCM_WTA_DISPATCH_1 (g_imag_part, z, SCM_ARG1, s_imag_part);
3994 }
0f2d19dd
JB
3995}
3996
3997
9de33deb 3998SCM_GPROC (s_magnitude, "magnitude", 1, 0, 0, scm_magnitude, g_magnitude);
1cc91f1b 3999
0f2d19dd 4000SCM
6e8d25a6 4001scm_magnitude (SCM z)
0f2d19dd 4002{
c2ff8ab0 4003 if (SCM_INUMP (z)) {
5986c47d
DH
4004 long int zz = SCM_INUM (z);
4005 if (zz >= 0) {
4006 return z;
4007 } else if (SCM_POSFIXABLE (-zz)) {
4008 return SCM_MAKINUM (-zz);
4009 } else {
4010#ifdef SCM_BIGDIG
4011 return scm_long2big (-zz);
4012#else
4013 scm_num_overflow (s_magnitude);
4014#endif
4015 }
c2ff8ab0 4016 } else if (SCM_BIGP (z)) {
5986c47d
DH
4017 if (!SCM_BIGSIGN (z)) {
4018 return z;
4019 } else {
4020 return scm_copybig (z, 0);
4021 }
c2ff8ab0
DH
4022 } else if (SCM_REALP (z)) {
4023 return scm_make_real (fabs (SCM_REAL_VALUE (z)));
4024 } else if (SCM_COMPLEXP (z)) {
4025 double r = SCM_COMPLEX_REAL (z);
4026 double i = SCM_COMPLEX_IMAG (z);
4027 return scm_make_real (sqrt (i * i + r * r));
4028 } else {
4029 SCM_WTA_DISPATCH_1 (g_magnitude, z, SCM_ARG1, s_magnitude);
4030 }
0f2d19dd
JB
4031}
4032
4033
9de33deb 4034SCM_GPROC (s_angle, "angle", 1, 0, 0, scm_angle, g_angle);
1cc91f1b 4035
0f2d19dd 4036SCM
6e8d25a6 4037scm_angle (SCM z)
0f2d19dd 4038{
f4c627b3
DH
4039 if (SCM_INUMP (z)) {
4040 if (SCM_INUM (z) >= 0) {
4041 return scm_make_real (atan2 (0.0, 1.0));
4042 } else {
4043 return scm_make_real (atan2 (0.0, -1.0));
f872b822 4044 }
f4c627b3
DH
4045 } else if (SCM_BIGP (z)) {
4046 if (SCM_BIGSIGN (z)) {
4047 return scm_make_real (atan2 (0.0, -1.0));
4048 } else {
4049 return scm_make_real (atan2 (0.0, 1.0));
0f2d19dd 4050 }
f4c627b3
DH
4051 } else if (SCM_REALP (z)) {
4052 return scm_make_real (atan2 (0.0, SCM_REAL_VALUE (z)));
4053 } else if (SCM_COMPLEXP (z)) {
4054 return scm_make_real (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
4055 } else {
4056 SCM_WTA_DISPATCH_1 (g_angle, z, SCM_ARG1, s_angle);
4057 }
0f2d19dd
JB
4058}
4059
4060
a1ec6916 4061SCM_DEFINE (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
1bbd0b84 4062 (SCM z),
bb628794 4063 "Returns an exact number that is numerically closest to Z.")
1bbd0b84 4064#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 4065{
c2ff8ab0 4066 if (SCM_INUMP (z)) {
f872b822 4067 return z;
c2ff8ab0 4068 } else if (SCM_BIGP (z)) {
f872b822 4069 return z;
c2ff8ab0
DH
4070 } else if (SCM_REALP (z)) {
4071 double u = floor (SCM_REAL_VALUE (z) + 0.5);
4072 long lu = (long) u;
4073 if (SCM_FIXABLE (lu)) {
4074 return SCM_MAKINUM (lu);
f872b822 4075#ifdef SCM_BIGDIG
c2ff8ab0
DH
4076 } else if (isfinite (u)) {
4077 return scm_dbl2big (u);
f872b822 4078#endif
c2ff8ab0
DH
4079 } else {
4080 scm_num_overflow (s_scm_inexact_to_exact);
4081 }
4082 } else {
4083 SCM_WRONG_TYPE_ARG (1, z);
4084 }
0f2d19dd 4085}
1bbd0b84 4086#undef FUNC_NAME
0f2d19dd
JB
4087
4088
0f2d19dd 4089#ifdef SCM_BIGDIG
0f2d19dd 4090/* d must be integer */
1cc91f1b 4091
0f2d19dd 4092SCM
6e8d25a6 4093scm_dbl2big (double d)
0f2d19dd
JB
4094{
4095 scm_sizet i = 0;
4096 long c;
4097 SCM_BIGDIG *digits;
4098 SCM ans;
f872b822
MD
4099 double u = (d < 0) ? -d : d;
4100 while (0 != floor (u))
4101 {
4102 u /= SCM_BIGRAD;
4103 i++;
4104 }
4105 ans = scm_mkbig (i, d < 0);
4106 digits = SCM_BDIGITS (ans);
4107 while (i--)
4108 {
4109 u *= SCM_BIGRAD;
4110 c = floor (u);
4111 u -= c;
4112 digits[i] = c;
4113 }
cf7c17e9 4114#ifndef SCM_RECKLESS
e1724d20 4115 if (u != 0)
52859adf 4116 scm_num_overflow ("dbl2big");
e1724d20 4117#endif
0f2d19dd
JB
4118 return ans;
4119}
4120
4121
4122
0f2d19dd 4123double
6e8d25a6 4124scm_big2dbl (SCM b)
0f2d19dd
JB
4125{
4126 double ans = 0.0;
f872b822
MD
4127 scm_sizet i = SCM_NUMDIGS (b);
4128 SCM_BIGDIG *digits = SCM_BDIGITS (b);
4129 while (i--)
4130 ans = digits[i] + SCM_BIGRAD * ans;
f3ae5d60
MD
4131 if (SCM_BIGSIGN (b))
4132 return - ans;
0f2d19dd
JB
4133 return ans;
4134}
f872b822 4135#endif
0f2d19dd 4136
1cc91f1b 4137
0f2d19dd 4138SCM
6e8d25a6 4139scm_long2num (long sl)
0f2d19dd 4140{
f872b822
MD
4141 if (!SCM_FIXABLE (sl))
4142 {
0f2d19dd 4143#ifdef SCM_BIGDIG
f872b822 4144 return scm_long2big (sl);
0f2d19dd 4145#else
f8de44c1 4146 return scm_make_real ((double) sl);
f872b822
MD
4147#endif
4148 }
4149 return SCM_MAKINUM (sl);
0f2d19dd
JB
4150}
4151
4152
5c11cc9d 4153#ifdef HAVE_LONG_LONGS
1cc91f1b 4154
0f2d19dd 4155SCM
6e8d25a6 4156scm_long_long2num (long_long sl)
0f2d19dd 4157{
f872b822
MD
4158 if (!SCM_FIXABLE (sl))
4159 {
0f2d19dd 4160#ifdef SCM_BIGDIG
f872b822 4161 return scm_long_long2big (sl);
0f2d19dd 4162#else
f8de44c1 4163 return scm_make_real ((double) sl);
f872b822
MD
4164#endif
4165 }
f2961ccd
DH
4166 else
4167 {
4168 /* we know that sl fits into an inum */
4169 return SCM_MAKINUM ((scm_bits_t) sl);
4170 }
0f2d19dd 4171}
0f2d19dd 4172
98cb6e75 4173#endif
0f2d19dd 4174
1cc91f1b 4175
0f2d19dd 4176SCM
6e8d25a6 4177scm_ulong2num (unsigned long sl)
0f2d19dd 4178{
f872b822
MD
4179 if (!SCM_POSFIXABLE (sl))
4180 {
0f2d19dd 4181#ifdef SCM_BIGDIG
f872b822 4182 return scm_ulong2big (sl);
0f2d19dd 4183#else
f8de44c1 4184 return scm_make_real ((double) sl);
f872b822
MD
4185#endif
4186 }
4187 return SCM_MAKINUM (sl);
0f2d19dd
JB
4188}
4189
1cc91f1b 4190
0f2d19dd 4191long
6e8d25a6 4192scm_num2long (SCM num, char *pos, const char *s_caller)
0f2d19dd 4193{
98cb6e75
DH
4194 if (SCM_INUMP (num)) {
4195 return SCM_INUM (num);
4196 } else if (SCM_BIGP (num)) {
4197 long int res;
4198 /* can't use res directly in case num is -2^31. */
4199 unsigned long int pos_res = 0;
4200 unsigned long int old_res = 0;
4201 scm_sizet l;
4202
4203 for (l = SCM_NUMDIGS (num); l--;) {
4204 pos_res = SCM_BIGUP (pos_res) + SCM_BDIGITS (num)[l];
4205 if (pos_res >= old_res) {
4206 old_res = pos_res;
4207 } else {
4208 /* overflow. */
4209 scm_out_of_range (s_caller, num);
4210 }
0f2d19dd 4211 }
98cb6e75
DH
4212 if (SCM_BIGSIGN (num)) {
4213 res = -pos_res;
4214 if (res <= 0) {
4215 return res;
4216 } else {
4217 scm_out_of_range (s_caller, num);
4218 }
4219 } else {
4220 res = pos_res;
4221 if (res >= 0) {
4222 return res;
4223 } else {
4224 scm_out_of_range (s_caller, num);
4225 }
0f2d19dd 4226 }
98cb6e75
DH
4227 } else if (SCM_REALP (num)) {
4228 double u = SCM_REAL_VALUE (num);
4229 long int res = u;
4230 if ((double) res == u) {
5c11cc9d 4231 return res;
98cb6e75
DH
4232 } else {
4233 scm_out_of_range (s_caller, num);
f872b822 4234 }
98cb6e75
DH
4235 } else {
4236 scm_wrong_type_arg (s_caller, (int) pos, num);
4237 }
0f2d19dd
JB
4238}
4239
4240
5c11cc9d 4241#ifdef HAVE_LONG_LONGS
1cc91f1b 4242
0f2d19dd 4243long_long
6e8d25a6 4244scm_num2long_long (SCM num, char *pos, const char *s_caller)
0f2d19dd 4245{
98cb6e75
DH
4246 if (SCM_INUMP (num)) {
4247 return SCM_INUM (num);
4248 } else if (SCM_BIGP (num)) {
4249 long long res;
4250 /* can't use res directly in case num is -2^63. */
4251 unsigned long long int pos_res = 0;
4252 unsigned long long int old_res = 0;
4253 scm_sizet l;
4254
4255 for (l = SCM_NUMDIGS (num); l--;) {
4256 pos_res = SCM_LONGLONGBIGUP (pos_res) + SCM_BDIGITS (num)[l];
4257 if (pos_res >= old_res) {
4258 old_res = pos_res;
4259 } else {
4260 /* overflow. */
4261 scm_out_of_range (s_caller, num);
4262 }
0f2d19dd 4263 }
98cb6e75
DH
4264 if (SCM_BIGSIGN (num)) {
4265 res = -pos_res;
4266 if (res <= 0) {
4267 return res;
4268 } else {
4269 scm_out_of_range (s_caller, num);
4270 }
4271 } else {
4272 res = pos_res;
4273 if (res >= 0) {
4274 return res;
4275 } else {
4276 scm_out_of_range (s_caller, num);
4277 }
f872b822 4278 }
98cb6e75
DH
4279 } else if (SCM_REALP (num)) {
4280 double u = SCM_REAL_VALUE (num);
4281 long long int res = u;
4282 if ((double) res == u) {
f872b822 4283 return res;
98cb6e75
DH
4284 } else {
4285 scm_out_of_range (s_caller, num);
f872b822 4286 }
98cb6e75
DH
4287 } else {
4288 scm_wrong_type_arg (s_caller, (int) pos, num);
4289 }
0f2d19dd 4290}
0f2d19dd 4291
98cb6e75 4292#endif
0f2d19dd 4293
1cc91f1b 4294
0f2d19dd 4295unsigned long
6e8d25a6 4296scm_num2ulong (SCM num, char *pos, const char *s_caller)
0f2d19dd 4297{
98cb6e75
DH
4298 if (SCM_INUMP (num)) {
4299 long nnum = SCM_INUM (num);
4300 if (nnum >= 0) {
4301 return nnum;
4302 } else {
4303 scm_out_of_range (s_caller, num);
4304 }
4305 } else if (SCM_BIGP (num)) {
4306 unsigned long int res = 0;
4307 unsigned long int old_res = 0;
4308 scm_sizet l;
4309
4310 for (l = SCM_NUMDIGS (num); l--;) {
4311 res = SCM_BIGUP (res) + SCM_BDIGITS (num)[l];
4312 if (res >= old_res) {
4313 old_res = res;
4314 } else {
4315 scm_out_of_range (s_caller, num);
4316 }
0f2d19dd 4317 }
98cb6e75
DH
4318 return res;
4319 } else if (SCM_REALP (num)) {
4320 double u = SCM_REAL_VALUE (num);
4321 unsigned long int res = u;
4322 if ((double) res == u) {
f872b822 4323 return res;
98cb6e75
DH
4324 } else {
4325 scm_out_of_range (s_caller, num);
f872b822 4326 }
98cb6e75
DH
4327 } else {
4328 scm_wrong_type_arg (s_caller, (int) pos, num);
4329 }
0f2d19dd
JB
4330}
4331
4332
0f2d19dd
JB
4333void
4334scm_init_numbers ()
0f2d19dd 4335{
f3ae5d60
MD
4336 scm_add_feature ("complex");
4337 scm_add_feature ("inexact");
5986c47d 4338 scm_flo0 = scm_make_real (0.0);
f872b822 4339#ifdef DBL_DIG
0f2d19dd 4340 scm_dblprec = (DBL_DIG > 20) ? 20 : DBL_DIG;
f872b822 4341#else
0f2d19dd
JB
4342 { /* determine floating point precision */
4343 double f = 0.1;
f872b822 4344 double fsum = 1.0 + f;
bb628794
DH
4345 while (fsum != 1.0) {
4346 if (++scm_dblprec > 20) {
4347 fsum = 1.0;
4348 } else {
f872b822 4349 f /= 10.0;
bb628794 4350 fsum = f + 1.0;
f872b822 4351 }
bb628794 4352 }
f872b822 4353 scm_dblprec = scm_dblprec - 1;
0f2d19dd 4354 }
f872b822 4355#endif /* DBL_DIG */
a0599745 4356#include "libguile/numbers.x"
0f2d19dd 4357}
89e00824
ML
4358
4359/*
4360 Local Variables:
4361 c-file-style: "gnu"
4362 End:
4363*/