Special floating point values have no encoding #2

Open
willglynn opened this Issue Sep 7, 2012 · 10 comments

Comments

Projects
None yet
9 participants

The "floating point numbers" section refers to 64-bit double precision -- presumably IEEE-754 -- and specifies how to encode typical numbers, but it does not specify encoding of special values such as NaN or infinities. This is undesirable, as now any object graph that includes any IEEE-754 floating point field could conceivably become unserializable, depending on the value that field contains.

JSON makes no allowances for NaN or +/-Inf, forcing tools to use tricks like serializing these values as strings, and coercing certain strings ("NaN") back into their floating-point counterparts on deserialization. Not only does this add semantics on an ad-hoc basis outside the JSON specification, it is simply too much magic for my taste. On the other hand, YAML provides .inf, -.Inf, and .NAN as language-independent tokens representing these particular floating point values. I find this much preferable, as it causes no ambiguity.

I'd like the encoding of these values to be specified, since edn seems to be aiming at general-purpose data interchange, and the set of floating point numbers includes these special values.

seh commented Sep 8, 2012

Looking around for precedent, neither Common Lisp nor Emacs Lisp have such literals, as neither accommodate the concept of infinite numbers. To get there, there are some implementation-specific extensions, requiring configuration of over- and underflow traps to put these to use:

  • CMUCL defines extensions:(short|single|double|long)-float-(posi|nega)tive-infinity.
  • SBCL defines sbt-ext:(short|single|double|long)-float-(posi|nega)tive-infinity.
  • The IEEE Floats library defines :not-a-number, :positive-infinity, and :negative-infinity.

cambecc commented Mar 26, 2013

For more precedent, clojure itself formats these special values as NaN, Infinity, and -Infinity:

user=> (/ 0.0 0.0)
NaN
user=> (/ 1.0 0.0)
Infinity
user=> (/ -1.0 0.0)
-Infinity

These same formats have precedent in the JVM, both on output:

System.out.println(Double.NaN);
System.out.println(Double.POSITIVE_INFINITY);
System.out.println(Double.NEGATIVE_INFINITY);

NaN
Infinity
-Infinity

...and input:

System.out.println(Double.valueOf("NaN"));
System.out.println(Double.valueOf("+NaN"));
System.out.println(Double.valueOf("-NaN"));
System.out.println(Double.valueOf("Infinity"));
System.out.println(Double.valueOf("+Infinity"));
System.out.println(Double.valueOf("-Infinity"));

NaN
NaN
NaN
Infinity
Infinity
-Infinity

edn should plug the hole left open by JSON and specify these special values as valid floating point numbers. The following grammar change would be sufficient:

floating-point-number
  int M
  int frac
  int exp
  int frac exp
  NaN
  +NaN
  -NaN
  Infinity
  +Infinity
  -Infinity

EDIT:

Actually, it is not so simple. The above grammar would make it impossible to distinguish between these special floating point numbers and symbols. One possible solution is to define a built-in tag:

#float NaN
#float Infinity
#float -Infinity

...or something of the sort.

This is satisfactory. I should note that this may not be transparent at the binary-representation-in-RAM level (NaNs carry a sign bit, a signaling flag, and a payload all of which are discarded), but this data loss is explicitly permitted by IEEE 754 under "External character sequences representing zeros, infinities, and NaNs". It's also semantically proper, since floats can still be encoded as floats, even if they're NaN.

Contributor

richhickey commented Jan 7, 2014

I am in favor of supporting these.
0.NaN 0.Inf -0.Inf ?

Bronsa commented Jan 9, 2014

How about simply making [+-]Infinity and NaN "special" symbols like true,false,nil?

We're running into this bug now, applying the patch from Jira CLJ-1074 seems to resolve it on 1.7 master, but it would be an improvement to not depend on a patched version.

http://dev.clojure.org/jira/browse/CLJ-1074

Is there a fix in the works? Or a more up to date conversation on why this hasn't been addressed?

Thanks,
Andrew

Andy Fingerhut responded to my similar question on CLJ-1074.

If anyone else runs into this, the tools.reader library handles +/-Infinity and NaN's sanely.

@joshua-g joshua-g referenced this issue in pixie-lang/pixie Aug 21, 2015

Open

floating point literals for +-Inf, NaN ? #362

Scheme (R6RS and R7RS) use the spellings +inf.0, -inf.0, and +nan.0, none of which are valid Scheme symbols. It also supports -0.0 and other ways to write floating-point negative zero.

rnewman commented Feb 4, 2017

For the EDN library we're building in Rust over at https://github.com/mozilla/mentat/, we independently settled on using #f as a dispatch character, simply because it's unambiguous (NaN could legitimately be a symbol) and brief.

(The EDN doc claims that all tokens should be prefixed, but that seems a waste of time when the spec itself is so incomplete.)

Did the community reach a consensus that isn't documented in this issue?

Landed in Clojure 1.9.0-alpha20 with https://dev.clojure.org/jira/browse/CLJ-1074 with ##Inf, ##-Inf and ##NaN. According a comment from Rich, should also be included in the edn spec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment