schemelispr5rsguilesisc

How can I convert a string into exact number in Scheme Lisp?


For example, I have this string: "6119726089.12814713"

If I do (string->number "6119726089.12814713") - using the SISC implementation the result is 6.119726089128147e9 - and in Guile implementation is 6119726089.128147 but I would like an exact number, like: 611972608912814713/100000000 without loss precision.

I'd like a function like (string->exact) or something like this.

NOTE: please fix my non-native English and remove this message. Thanks.


Solution

  • Use (string->number "#e6119726089.12814713") to parse the number as exact. This works for at least Racket and Guile. It may not work correctly on other Scheme implementations, however; they are at liberty to parse as inexact first, then convert.


    Here's a portable implementation of the string->exact function that the OP asked for. I've manually tested it with a range of inputs, but you should do your own testing to ensure it fits your needs:

    (define (string->exact str)
      (define zero (char->integer #\0))
      (let loop ((result #f)
                 (factor 1)
                 (seen-dot? #f)
                 (digits (string->list str)))
        (if (null? digits)
            (and result (/ result factor))
            (let ((cur (car digits))
                  (next (cdr digits)))
              (cond ((and (not result) (not seen-dot?) (char=? cur #\-))
                     (loop result (- factor) seen-dot? next))
                    ((and (not seen-dot?) (char=? cur #\.))
                     (loop result factor #t next))
                    ((char<=? #\0 cur #\9)
                     (loop (+ (* (or result 0) 10) (- (char->integer cur) zero))
                           (if seen-dot? (* factor 10) factor)
                           seen-dot? next))
                    (else #f))))))