On Numbers and Strings

Here we devise some auxiliary code that will convert a number to a string and vice versa. These two routines are |number->string| and |string->number|. The standard requires that |(string->number| |(number->string n))| be |n| for all numerical |n|, but the reverse composition does not have the same property.

The code handles in scheme the special case of integers, as they can only be dealt with through |bignum| operations, which are not appropriately callable from the C kernel. Floating-point conversion, though, is done by calls to |sprintf| and |sscanf|. These has the advantage of being highly standard, as well as requiring little effort from myself...

(letrec ((0-hexa (char->integer #)) (10-hexa (- (char->integer #) 10)) (get-base (lambda (args) (if (null? (cdr args)) (case (car args) (() 10) ((2 8 10 16) (car args)) (else (error "Invalid base" (car args)))) (error "Gimme 2 args, please" args)))) (integer->string (lambda (num base) (define (integer->list num) (do ((num num (quotient num base)) (result '() (let ((digit (remainder num base))) (cons (integer->char (+ digit (if (> digit 9) 10-hexa 0-hexa))) result)))) ((zero? num) result))) (cond ((negative? num) (string-append "-" (integer->string (- num) base))) ((zero? num) "0") (else (list->string (integer->list num)))))) (list->integer (lambda (lyst base) (call-with-current-continuation (lambda (cont) (let ((negative (equal? (car lyst) #))) (do ((lyst (if negative (cdr lyst) lyst) (cdr lyst)) (result 0 (+ (* result base) (let* ((c (char-upcase (car lyst))) (head (cond ((char>=? c #) (- (char->integer c) 10-hexa)) ((char>=? c #) (- (char->integer c) 0-hexa)) (else (cont #F))))) (if (< head base) head (cont #F)))))) ((null? lyst) (if negative (- result) result)))))))) ) (set! number->string (lambda (num . args) (let ((base (get-base args))) (cond ((integer? num) (integer->string num base)) ((number? num) (if (= base 10) (sprintf "(error "Invalid base" base))) (else (error "Argument must be number" num)))))) (set! string->number (lambda (str . args) (let* ((base (get-base args)) (first-shot (list->integer (string->list str) base))) (if (and (integer? first-shot) (not (equal? str "-"))) first-shot (if (= base 10) (let ((second-shot (sscanf str "(if (= (length second-shot) 1) (car second-shot) #F)) #F))))) )