~ chicken-core (chicken-5) 14b2d48ca65a2e53af484ebd363a2c58b5dc8b0c
commit 14b2d48ca65a2e53af484ebd363a2c58b5dc8b0c Author: felix <felix@call-with-current-continuation.org> AuthorDate: Sun Apr 4 22:57:26 2010 +0200 Commit: felix <felix@call-with-current-continuation.org> CommitDate: Sun Apr 4 22:57:26 2010 +0200 applied patch by Christian Kellermann for number->string conversion with arbitrary base diff --git a/chicken.h b/chicken.h index 8e9e539e..4f122484 100644 --- a/chicken.h +++ b/chicken.h @@ -572,6 +572,7 @@ typedef unsigned __int64 uint64_t; #define C_BAD_ARGUMENT_TYPE_NO_TAGGED_POINTER_ERROR 32 #define C_BAD_ARGUMENT_TYPE_NO_FLONUM_ERROR 33 #define C_BAD_ARGUMENT_TYPE_NO_CLOSURE_ERROR 34 +#define C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR 35 /* Platform information */ diff --git a/library.scm b/library.scm index fcc476d5..7e45b9bf 100644 --- a/library.scm +++ b/library.scm @@ -3728,6 +3728,7 @@ EOF ((32) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a tagged pointer" args)) ((33) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a flonum" args)) ((34) (apply ##sys#signal-hook #:type-error loc "bad argument type - not a procedure" args)) + ((35) (apply ##sys#signal-hook #:type-error loc "bad argument type - invalid base" args)) (else (apply ##sys#signal-hook #:runtime-error loc "unknown internal error" args)) ) ) ) ) diff --git a/manual/Extensions to the standard b/manual/Extensions to the standard index 51e8664b..7b88a0b5 100644 --- a/manual/Extensions to the standard +++ b/manual/Extensions to the standard @@ -157,6 +157,11 @@ The latter is encoded in UTF-8 format. The third argument to {{substring}} is optional and defaults to the length of the string. +=== Number/String conversions + +The optional "base" argument to{{string->number}} and {{number->string}} +may be any integral value from 2 to 36. + === {{force}} {{force}} called with an argument that is not a promise returns diff --git a/runtime.c b/runtime.c index 6959a83f..c7214f47 100644 --- a/runtime.c +++ b/runtime.c @@ -1582,6 +1582,11 @@ void barf(int code, char *loc, ...) c = 1; break; + case C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR: + msg = C_text("bad argument type - invalid base"); + c = 1; + break; + default: panic(C_text("illegal internal error code")); } @@ -7038,7 +7043,7 @@ void C_ccall C_string_to_number(C_word c, C_word closure, C_word k, C_word str, va_end(v); if(radix & C_FIXNUM_BIT) radix = C_unfix(radix); - else barf(C_BAD_ARGUMENT_TYPE_ERROR, "string->number", radix); + else barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "string->number", radix); } else C_bad_argc(c, 3); @@ -7215,18 +7220,17 @@ C_regparm C_word C_fcall convert_string_to_number(C_char *str, int radix, C_word } } - -static char *to_binary(C_uword num) +static char *to_n_nary(C_uword num, C_uword base) { char *p; - - buffer[ 66 ] = '\0'; + char digits[] ={ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; + buffer [ 66 ] = '\0'; p = buffer + 66; - + do { - *(--p) = (num & 1) ? '1' : '0'; - num /= 2; - } while(num); + *(--p) = digits [ num % base ]; + num /= base; + } while (num); return p; } @@ -7247,7 +7251,7 @@ void C_ccall C_number_to_string(C_word c, C_word closure, C_word k, C_word num, va_end(v); if(radix & C_FIXNUM_BIT) radix = C_unfix(radix); - else barf(C_BAD_ARGUMENT_TYPE_ERROR, "number->string", radix); + else barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", radix); } else C_bad_argc(c, 3); @@ -7259,11 +7263,11 @@ void C_ccall C_number_to_string(C_word c, C_word closure, C_word k, C_word num, num = -num; } + if((radix < 2) || (radix > 16)){ + barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", C_fix(radix)); + } + switch(radix) { - case 2: - p = to_binary(num); - break; - #ifdef C_SIXTY_FOUR case 8: C_sprintf(p = buffer + 1, C_text("%lo"), num); break; case 10: C_sprintf(p = buffer + 1, C_text("%ld"), num); break; @@ -7273,8 +7277,8 @@ void C_ccall C_number_to_string(C_word c, C_word closure, C_word k, C_word num, case 10: C_sprintf(p = buffer + 1, C_text("%d"), num); break; case 16: C_sprintf(p = buffer + 1, C_text("%x"), num); break; #endif - - default: barf(C_BAD_ARGUMENT_TYPE_ERROR, "number->string", C_fix(radix)); + default: + p = to_n_nary(num, radix); } } else if(!C_immediatep(num) && C_block_header(num) == C_FLONUM_TAG) { @@ -7286,11 +7290,11 @@ void C_ccall C_number_to_string(C_word c, C_word closure, C_word k, C_word num, f = -f; } - switch(radix) { - case 2: - p = to_binary((unsigned int)f); - goto fini; + if((radix < 2) || (radix > 16)){ + barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "number->string", C_fix(radix)); + } + switch(radix) { case 8: C_sprintf(p = buffer, "%o", (unsigned int)f); goto fini; @@ -7298,6 +7302,11 @@ void C_ccall C_number_to_string(C_word c, C_word closure, C_word k, C_word num, case 16: C_sprintf(p = buffer, "%x", (unsigned int)f); goto fini; + + default: + p = to_n_nary((unsigned int)f, radix); + goto fini; + } } diff --git a/tests/library-tests.scm b/tests/library-tests.scm index ec59bf60..a58b5960 100644 --- a/tests/library-tests.scm +++ b/tests/library-tests.scm @@ -1,5 +1,7 @@ ;;;; library-tests.scm +(use srfi-1) + ;; numbers @@ -35,6 +37,13 @@ (99.2 10) (-99.2 10))) +;; by Christian Kellermann +(assert + (equal? + (map (lambda (n) (number->string 32 n)) (iota 15 2)) + '("100000" "1012" "200" "112" "52" "44" "40" "35" "32" "2A" "28" "26" "24" "22" "20"))) + + ;; fp-math (assert (= (sin 42.0) (fpsin 42.0))) @@ -59,4 +68,3 @@ (assert (= -42.0 (fpceiling -42.2))) (assert (not (fpinteger? 2.3))) (assert (fpinteger? 1.0)) -Trap