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