Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Converting String to Float

7 views
Skip to first unread message

Ray Drew

unread,
Dec 17, 1997, 3:00:00 AM12/17/97
to

Is there a float equivalent to parse-integer? I can't find any reference to
one but thought I'd check before writing my own.

--
Ray Drew
CIA MediaSystems
London
rd...@cia-group.com

Michael Tuchman

unread,
Dec 17, 1997, 3:00:00 AM12/17/97
to

"Ray Drew" <rd...@cia-group.com> wrote:

>Is there a float equivalent to parse-integer? I can't find any reference to
>one but thought I'd check before writing my own.
>
>--

read would work in many cases - use something like this

(parse-float (str)
(handler-case
(read-from-string str nil)
(error (c)
;; return whatever you want here if str does not parse to a float
)))


that's my .02 - I've already used code like this in my application.
(for better or for worse :-)

hope this helps!

Erik Naggum

unread,
Dec 17, 1997, 3:00:00 AM12/17/97
to

* Ray Drew

| Is there a float equivalent to parse-integer? I can't find any reference to
| one but thought I'd check before writing my own.

I'd recommend implementing your own based on `read-from-string'.

unfortunately, there's no hook (standard or otherwise, to my knowledge)
into the decision process after a string of characters has been read as a
token (of constituent characters), so it's hard to bail out before it is
interpreted as a symbol if it is not a number, so you might want to check
the set of characters that this string consists of before you call
`read-from-string'.

#\Erik
--
If you think this year is number 97, | Help fight MULE in GNU Emacs 20!
_you_ are not "Year 2000 Compliant". | http://sourcery.naggum.no/emacs/

Kent M Pitman

unread,
Dec 17, 1997, 3:00:00 AM12/17/97
to

mft@no_spam.mindspring.com (Michael Tuchman) writes:

> "Ray Drew" <rd...@cia-group.com> wrote:
>
> >Is there a float equivalent to parse-integer? I can't find any reference to
> >one but thought I'd check before writing my own.
>

> read would work in many cases - use something like this
>
> (parse-float (str)
> (handler-case
> (read-from-string str nil)
> (error (c)
> ;; return whatever you want here if str does not parse to a float
> )))

I recommend at least testing if the string is plausibly a float
to avoid trojan horses and/or result type errors.

e.g., something like the following might do. (By the way, I only
tested on a couple of examples and it might be buggy... use at your
own risk.)

(defun parse-float (string &key (start 0) end)
(check-type start fixnum "a string start position")
(check-type end (or null fixnum) "a string stop position")
(let ((start start) (stop (or end (length string))))
(declare (fixnum start stop))
(or (when (and (> (- stop start) 0)
(find (char string start) "+-.01234556789")
(loop for i from (the fixnum (1+ start)) below stop
always (find (char string i) "0123456789.efsdl")))
(let ((result (read-from-string string nil nil :start start :end stop)))
(if (floatp result)
result nil)))
(error "Not float syntax: ~S" string))))

You might or might not want to check that (< (count #\. string) 2) and
(loop for i from start below stop thereis (digit-char-p (char string i)))
but since read-from-string will redundantly test that, I didn't bother.
It just risks some extra consing if read-from-string does it because it
will likely intern a symbol in many such cases, slightly bloating memory
in a non-GC-able way for each such error. (If you were paranoid about
this, you could bind package to a throwaway package and unintern any symbol
results.)

Btw, I agree that computationally this is really gonna slow a lot of things down.
(And probably you should signal an error of an appropriate condition class, not
just call error with an error message string.)

FWIW, I'm firmly aware that this is all gross. I've had to do it for
several things I've worked on and it makes me horribly sick to my
stomach every time I do it. A built-in parse-float (especially since the
code is there and just needs an entry point!) is on my to-request list
for next round standardization.

Aleksandar Bakic

unread,
Dec 17, 1997, 3:00:00 AM12/17/97
to Ray Drew

This might help:

(defun parse-real (str &key (rationalize nil))
(if (and (stringp str) (string/= str ""))
(if rationalize
(parse-real-helper 0 nil
(string-left-trim
'(#\Space #\Tab #\Newline)
(string-right-trim
'(#\Space #\Tab #\Newline) str)))
(float
(parse-real-helper 0 nil
(string-left-trim
'(#\Space #\Tab #\Newline)
(string-right-trim
'(#\Space #\Tab #\Newline) str)))))
(error "PARSE-REAL: string ~S has no real syntax" str)))

(defun parse-real-helper (val decimal str)
(if (string= str "")
val
(let ((cur-char (char str 0))
(new-val val)
(new-decimal (when decimal (- decimal 1))))
(cond
((digit-char-p cur-char)
(if decimal
(setq new-val (+ val (* (digit-char-p cur-char) (expt 10
new-decimal
))))
(setq new-val (+ (* val 10) (digit-char-p cur-char)))))
((char= #\. cur-char)
(setq new-decimal 0))
(t
(error "PARSE-REAL: string ~S has no real syntax" str)))
(parse-real-helper new-val new-decimal (subseq str 1)))))

Regards,
Aleksandar

Ray Drew wrote:
>
> Is there a float equivalent to parse-integer? I can't find any reference to
> one but thought I'd check before writing my own.
>

> --

Pierpaolo Bernardi

unread,
Dec 18, 1997, 3:00:00 AM12/18/97
to

Ray Drew (rd...@cia-group.com) wrote:
: Is there a float equivalent to parse-integer? I can't find any reference to
: one but thought I'd check before writing my own.

read-from-string

P.

Francis Leboutte

unread,
Dec 18, 1997, 3:00:00 AM12/18/97
to

"Ray Drew" <rd...@cia-group.com> wrote:

>Is there a float equivalent to parse-integer? I can't find any reference to
>one but thought I'd check before writing my own.

Here is a version of parse-float from the CMU Lisp repository I have
written for my current needs. Tested and to be used in ACL4W (only one
floating point type).

Francis


(declaim (inline whitespace-p))
(defun whitespace-p (char)
(declare (OPTIMIZE (speed 3) (safety 1)))
(char= char #\space))
(declaim (notinline whitespace-p))

#+never
(progn
(parse-float "" 0 nil)
;;;1.> 0.0
;;;2.> 0
(parse-float " -135" 0 nil)
;;;1.> -135.0
;;;2.> 5
(parse-float " 135.23" 0 nil)
;;;1.> 135.23
;;;2.> 7
(parse-float " 135.23e-3" 0 nil)
;;;1.> 0.13523
;;;2.> 10
(parse-float "135.23F-3" 0 nil)
;;;1.> 0.13523
;;;2.> 9
(parse-float " e" 0 nil)
;;;1.> 0.0
;;;2.> 2
(parse-float " -" 0 nil)
;;;1.> 0.0
;;;2.> 2
(parse-float "- " 0 nil)
;;;1.> 0.0
;;;2.> 1
(parse-float " ." 0 nil)
;;;1.> 0.0
;;;2.> 2
(parse-float " . " 0 nil)
;;;1.> 0.0
;;;2.> 2
(parse-float " -.7" 0 nil)
;;;1.> -0.7
;;;2.> 4
(parse-float " " 0 nil)
;;;1.> 0.0
;;;2.> 1
)
(defun parse-float (string start end)
"Based on parse-float from CMU Lisp repository, by Mark Kantrowitz"
(declare (OPTIMIZE (speed 3) (safety 1)))
(declare (INLINE whitespace-p))
(setq end (or end (length string)))
(let ((index (or (position-if-not #'whitespace-p string
:start start :end end)
(return-from parse-float (values 0.0 end))))
(minusp nil) (decimalp nil) (found-digit nil)
(before-decimal 0) (after-decimal 0) (decimal-counter 0)
(exponent 0)
(result 0)
(radix 10))
(declare (fixnum index))
(let ((char (char string index)))
(cond ((char= char #\-)
(setq minusp t)
(incf index))
((char= char #\+)
(incf index))))
(loop
until (i= index end)
for char = (char string index)
as weight = (digit-char-p char radix)
do
(cond ((and weight (not decimalp))
(setq before-decimal (+ weight (* before-decimal radix))
found-digit t))
((and weight decimalp)
(setq after-decimal (+ weight (* after-decimal radix))
found-digit t)
(incf decimal-counter))
((and (char= char #\.) (not decimalp))
(setq decimalp t))
((and (or (char-equal char #\E)
(char-equal char #\D)
(char-equal char #\F)
(char-equal char #\S)
(char-equal char #\L))
(= radix 10))
(multiple-value-bind (num idx)
(parse-integer string :start (1+ index) :end end
:radix radix :junk-allowed NIL)
(setq exponent (or num 0)
index idx)
(when (i= index end) (return nil))))
((whitespace-p char)
(when (position-if-not #'whitespace-p string
:start (1+ index) :end end)
(error "There's junk in this string: ~S." string))
(return nil))
(t
(error "There's junk in this string: ~S." string)))
(iincf index))
(setq result (coerce (* (+ before-decimal
(* after-decimal
(coerce (expt radix (-
decimal-counter))
'float)))
(coerce (expt radix exponent)
'float))
'float))
(values
(if found-digit
(if minusp (- result) result)
0.0)
index)))

--
Francis Leboutte
f.leb...@skynet.be lebo...@acm.org http://users.skynet.be/algo
Marre du courrier non sollicité (spam)? Visitez http://www.cauce.org

0 new messages