I am using Cuerdas library in a
ClojureScript program to parse floating point numbers. Sometimes the input from
a user is missing the integral part, like .1
for 0.1
. I need to handle this.
But I ran into strange results when comparing the parsed numbers:
(= 0.1 (parse-number "0.1"))
;; => true
(= .1 (parse-number "0.1"))
;; => true
(= 0.1 (parse-number ".1"))
;; => false
(= .1 (parse-number ".1"))
;; => false
The last two results above are surprising to me. When comparing literal number I get the expected result:
(= 0 .0)
;; => true
The strange behavior is also visible when I just parse the decimal number without integer part, like here:
(parse-number ".1")
;; => .1
.1
;; => 0.1
I found out that I can use js/parseFloat
to get what I want, but I'm curious
what is the reason for this behavior when using Cuerdas? What is this .1
value
and how is it different than 0.1
?
parse-number
source looked like this:
(defn parse-number
"General purpose function for parse number like
string to number. It works with both integers
and floats."
[s]
(if (nil? s)
#?(:cljs js/NaN :clj Double/NaN)
(if (numeric? s)
(edn/read-string s)
#?(:cljs js/NaN :clj Double/NaN))))
Both ".1"
and "0.1"
are considered to be numeric?
(was implemented in cuerdas by a regex check):
cljs.user=> (def re #"^[+-]?([0-9]*\.?[0-9]+|[0-9]+\.?[0-9]*)([eE][+-]?[0-9]+)?$")
#'cljs.user/re
cljs.user=> (boolean (re-matches re "0.1"))
true
cljs.user=> (boolean (re-matches re ".1"))
true
so they will be read by cljs.reader/read-string
.
When reading the string "0.1"
the return type is a js/Number
, but ".1"
is of type cljs.core/Symbol
:
cljs.user=> (cljs.reader/read-string ".1")
.1
cljs.user=> (cljs.reader/read-string "0.1")
0.1
cljs.user=> (type (cljs.reader/read-string "0.1"))
#object[Number]
cljs.user=> (type (cljs.reader/read-string ".1"))
cljs.core/Symbol
So although it looks like it correctly parsed the .1 it actually turned it into a symbol. The symbol .1
is not equal to the number .1
.
Note that parse-number
is no longer available in newer versions of cuerdas because it "is a string manipulation library not a numbers parsing library".