1
/*===========================================================================
5
* Copyright (C) 2005-2006 Kazuki Ohta <mover AT hct.zaq.ne.jp>
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of authors nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
22
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
23
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
26
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
===========================================================================*/
37
/*=======================================
39
=======================================*/
44
/*=======================================
46
=======================================*/
47
#include "sigscheme.h"
48
#include "sigschemeinternal.h"
50
/*=======================================
51
File Local Struct Declarations
52
=======================================*/
54
/*=======================================
55
File Local Macro Declarations
56
=======================================*/
58
/*=======================================
60
=======================================*/
62
/*=======================================
63
File Local Function Declarations
64
=======================================*/
65
static int prepare_radix(const char *funcname, ScmObj args);
67
/*=======================================
68
Function Implementations
69
=======================================*/
70
/*=======================================
72
=======================================*/
73
/*===========================================================================
74
R5RS : 6.2 Numbers : 6.2.5 Numerical Operations
75
===========================================================================*/
76
/* Note: SigScheme supports only the integer part of the numerical tower. */
79
scm_p_add(ScmObj left, ScmObj right, enum ScmReductionState *state)
82
DECLARE_FUNCTION("+", reduction_operator);
86
case SCM_REDUCE_PARTWAY:
89
result = SCM_INT_VALUE(left);
93
result += SCM_INT_VALUE(right);
98
SCM_ASSERT(scm_false);
101
return MAKE_INT(result);
105
scm_p_multiply(ScmObj left, ScmObj right, enum ScmReductionState *state)
108
DECLARE_FUNCTION("*", reduction_operator);
112
case SCM_REDUCE_PARTWAY:
113
case SCM_REDUCE_LAST:
115
result = SCM_INT_VALUE(left);
119
result *= SCM_INT_VALUE(right);
124
SCM_ASSERT(scm_false);
127
return MAKE_INT(result);
131
scm_p_subtract(ScmObj left, ScmObj right, enum ScmReductionState *state)
134
DECLARE_FUNCTION("-", reduction_operator);
138
case SCM_REDUCE_PARTWAY:
139
case SCM_REDUCE_LAST:
141
result = SCM_INT_VALUE(left);
145
result -= SCM_INT_VALUE(right);
149
ERR("at least 1 argument required");
151
SCM_ASSERT(scm_false);
153
return MAKE_INT(result);
157
scm_p_divide(ScmObj left, ScmObj right, enum ScmReductionState *state)
160
DECLARE_FUNCTION("/", reduction_operator);
164
case SCM_REDUCE_PARTWAY:
165
case SCM_REDUCE_LAST:
167
result = SCM_INT_VALUE(left);
171
if (SCM_INT_VALUE(right) == 0)
172
ERR("division by zero");
173
result /= SCM_INT_VALUE(right);
176
ERR("at least 1 argument required");
178
SCM_ASSERT(scm_false);
180
return MAKE_INT(result);
184
scm_p_numberp(ScmObj obj)
186
DECLARE_FUNCTION("number?", procedure_fixed_1);
188
return MAKE_BOOL(NUMBERP(obj));
192
scm_p_integerp(ScmObj obj)
194
DECLARE_FUNCTION("integer?", procedure_fixed_1);
196
return MAKE_BOOL(INTP(obj));
199
#define COMPARATOR_BODY(op) \
203
ERR("at least 2 arguments required"); \
204
case SCM_REDUCE_PARTWAY: \
205
case SCM_REDUCE_LAST: \
208
if (SCM_INT_VALUE(left) op SCM_INT_VALUE(right)) \
209
return *state == SCM_REDUCE_LAST ? SCM_TRUE : right; \
210
*state = SCM_REDUCE_STOP; \
213
SCM_ASSERT(scm_false); \
218
scm_p_equal(ScmObj left, ScmObj right, enum ScmReductionState *state)
220
DECLARE_FUNCTION("=", reduction_operator);
226
scm_p_less(ScmObj left, ScmObj right, enum ScmReductionState *state)
228
DECLARE_FUNCTION("<", reduction_operator);
234
scm_p_less_equal(ScmObj left, ScmObj right, enum ScmReductionState *state)
236
DECLARE_FUNCTION("<=", reduction_operator);
242
scm_p_greater(ScmObj left, ScmObj right, enum ScmReductionState *state)
244
DECLARE_FUNCTION(">", reduction_operator);
250
scm_p_greater_equal(ScmObj left, ScmObj right, enum ScmReductionState *state)
252
DECLARE_FUNCTION(">=", reduction_operator);
257
#undef COMPARATOR_BODY
260
scm_p_zerop(ScmObj n)
262
DECLARE_FUNCTION("zero?", procedure_fixed_1);
266
return MAKE_BOOL(SCM_INT_VALUE(n) == 0);
270
scm_p_positivep(ScmObj n)
272
DECLARE_FUNCTION("positive?", procedure_fixed_1);
276
return MAKE_BOOL(SCM_INT_VALUE(n) > 0);
280
scm_p_negativep(ScmObj n)
282
DECLARE_FUNCTION("negative?", procedure_fixed_1);
286
return MAKE_BOOL(SCM_INT_VALUE(n) < 0);
292
DECLARE_FUNCTION("odd?", procedure_fixed_1);
296
return MAKE_BOOL(SCM_INT_VALUE(n) & 0x1);
300
scm_p_evenp(ScmObj n)
302
DECLARE_FUNCTION("even?", procedure_fixed_1);
306
return MAKE_BOOL(!(SCM_INT_VALUE(n) & 0x1));
310
scm_p_max(ScmObj left, ScmObj right, enum ScmReductionState *state)
312
DECLARE_FUNCTION("max", reduction_operator);
314
if (*state == SCM_REDUCE_0)
315
ERR("at least 1 argument required");
319
return (SCM_INT_VALUE(left) > SCM_INT_VALUE(right)) ? left : right;
323
scm_p_min(ScmObj left, ScmObj right, enum ScmReductionState *state)
325
DECLARE_FUNCTION("min", reduction_operator);
327
if (*state == SCM_REDUCE_0)
328
ERR("at least 1 argument required");
332
return (SCM_INT_VALUE(left) < SCM_INT_VALUE(right)) ? left : right;
340
DECLARE_FUNCTION("abs", procedure_fixed_1);
344
n = SCM_INT_VALUE(_n);
346
return (n < 0) ? MAKE_INT(-n) : _n;
350
scm_p_quotient(ScmObj _n1, ScmObj _n2)
353
DECLARE_FUNCTION("quotient", procedure_fixed_2);
358
n1 = SCM_INT_VALUE(_n1);
359
n2 = SCM_INT_VALUE(_n2);
362
ERR("division by zero");
364
return MAKE_INT((int)(n1 / n2));
368
scm_p_modulo(ScmObj _n1, ScmObj _n2)
370
scm_int_t n1, n2, rem;
371
DECLARE_FUNCTION("modulo", procedure_fixed_2);
376
n1 = SCM_INT_VALUE(_n1);
377
n2 = SCM_INT_VALUE(_n2);
380
ERR("division by zero");
383
if (n1 < 0 && n2 > 0) {
385
} else if (n1 > 0 && n2 < 0) {
389
return MAKE_INT(rem);
393
scm_p_remainder(ScmObj _n1, ScmObj _n2)
396
DECLARE_FUNCTION("remainder", procedure_fixed_2);
401
n1 = SCM_INT_VALUE(_n1);
402
n2 = SCM_INT_VALUE(_n2);
405
ERR("division by zero");
407
return MAKE_INT(n1 % n2);
410
/*===========================================================================
411
R5RS : 6.2 Numbers : 6.2.6 Numerical input and output
412
===========================================================================*/
415
prepare_radix(const char *funcname, ScmObj args)
419
DECLARE_INTERNAL_FUNCTION("(internal)");
421
ASSERT_PROPER_ARG_LIST(args);
423
/* dirty hack to replace internal function name */
424
SCM_MANGLE(name) = funcname;
430
ASSERT_NO_MORE_ARG(args);
432
r = SCM_INT_VALUE(radix);
433
if (!(r == 2 || r == 8 || r == 10 || r == 16))
434
ERR_OBJ("invalid radix", radix);
441
scm_p_number2string(ScmObj num, ScmObj args)
443
char buf[sizeof("-") + SCM_INT_BITS];
447
/* 'un' must be unsinged to be capable of -INT_MIN */
448
scm_uint_t un, digit, r;
450
DECLARE_FUNCTION("number->string", procedure_variadic_1);
454
n = SCM_INT_VALUE(num);
457
r = (scm_uint_t)prepare_radix(SCM_MANGLE(name), args);
459
end = p = &buf[sizeof(buf) - 1];
464
*--p = (digit <= 9) ? '0' + digit : 'a' + digit - 10;
469
return MAKE_STRING_COPYING(p, end - p);
473
scm_string2number(const char *str, int radix, scm_bool *err)
478
DECLARE_INTERNAL_FUNCTION("string->number");
482
* - If string is not a syntactically valid notation for a number, then
483
* `string->number' returns #f.
485
* - `String->number' is permitted to return #f whenever string contains an
486
* explicit radix prefix.
488
* - If all numbers supported by an implementation are real, then
489
* `string->number' is permitted to return #f whenever string uses the
490
* polar or rectangular notations for complex numbers.
492
* - If all numbers are integers, then `string->number' may return #f
493
* whenever the fractional notation is used.
495
* - If all numbers are exact, then `string->number' may return #f whenever
496
* an exponent marker or explicit exactness prefix is used, or if a #
497
* appears in place of a digit.
499
* - If all inexact numbers are integers, then `string->number' may return
500
* #f whenever a decimal point is used.
503
#if (SIZEOF_SCM_INT_T <= SIZEOF_LONG)
504
n = (scm_int_t)strtol(str, &end, radix);
505
#elif (HAVE_STRTOLL && SIZEOF_SCM_INT_T <= SIZEOF_LONG_LONG)
506
n = (scm_int_t)strtoll(str, &end, radix);
507
#elif (HAVE_STRTOIMAX && Sizeof_SCM_INT_T <= SIZEOF_INTMAX_T)
508
n = (scm_int_t)strtoimax(str, &end, radix);
510
#error "This platform is not supported"
513
if (errno == ERANGE || n < SCM_INT_MIN || SCM_INT_MAX < n)
514
ERR("fixnum limit exceeded: %d", n);
516
empty_strp = (end == str); /* apply the first rule above */
517
*err = (empty_strp || *end);
522
scm_p_string2number(ScmObj str, ScmObj args)
528
DECLARE_FUNCTION("string->number", procedure_variadic_1);
532
c_str = SCM_STRING_STR(str);
533
r = prepare_radix(SCM_MANGLE(name), args);
535
ret = scm_string2number(c_str, r, &err);
536
return (err) ? SCM_FALSE : MAKE_INT(ret);