GithubHelp home page GithubHelp logo

Ugh signed zeros about circe HOT 4 CLOSED

circe avatar circe commented on July 3, 2024
Ugh signed zeros

from circe.

Comments (4)

ceedubs avatar ceedubs commented on July 3, 2024

I don't have any helpful input on your suggestion, but I just want to 👏 for an excellent writeup with an introductory paragraph that guaranteed I would read on.

from circe.

non avatar non commented on July 3, 2024

So, first of all, welcome to the hell that is IEEE-754 on the JVM.

We're talking about floating-point, so obviously things are going to be terrible no matter what we do. I'm going to lay out my own feelings on the "right thing" to do, with the proviso that there are obviously problems.

First of all, I have accepted that type classes parameterized on Double or Float are usually not law-abiding. This is already true for associativity and Semigroup[Double]. Similarly, NaN violates the identity/inverse interaction for Group[Double] (we'd like for (x |+| x.inverse) = empty but try it with NaN).

Given this background, I think Algebra's behavior is wrong and Scalaz's is correct. eqv(x, y) and x == y should produce the same results, especially since == 0.0 checks will be very common. I feel strongly like a generic version of direct code shouldn't change the meaning. This does create an inconsistency between eqv and compare: the former will report equal, the latter will return a non-equal ordering.

The reason I mentioned floating-point type class instances not being law-abiding is that Scalaz's instance (like Spire's) breaks the law that eqv(x, y) = compare(x, y) == 0. Algebra's implementation of eqv for Eq[Double] defaulted to compare(x, y) == 0 which is why it deviates from the other implementations.

The other "advantage" of this view is that it keeps things like eqv(NaN, NaN) doing the same thing as NaN == NaN. Again, we can argue about whether IEEE-754 is crazy or not, but changing the behavior between direct and generic code seems really bad from my POV. If someone wants to call compare (or java.lang.Double.compare) then that's their problem, but using operators like === or < in generic code should be consistent with operators like == and < in direct code.

So what should Circe do? I propose one of these:

  1. Normalize the JSON value -0.0 as the Double value 0.0. This won't break any code that isn't specifically relying on signed-zero behavior. Since JSON doesn't guarantee IEEE-754 semantics I think this is probably fine. Given that JSON does not allow infinities or NaNs, this frees you from the last of the weird sentinel value warts that come with Double. I think this is probably the best option.
  2. Pass it through and let someone else worry about it. If you really want to support someone who wants to encode signed zeros in JSON, then just leave these values alone and let someone else worry about it. Given that signed zeros are mostly designed to help deal with certain kinds of symmetry errors in numerical analysis, I think it's relatively unlikely that they will crop up in JSON values, but if they do, we can just kick the can down the road and let someone else worry about them.

Obviously my plan embraces inconsistency, but due to the interaction of IEEE and Java there is fundamental inconsistency between double and java.lang.Double which is literally impossible to fix. All we can do is to try to minimize the pain in particular cases.

from circe.

travisbrown avatar travisbrown commented on July 3, 2024

Thanks for the detailed answer, @non!

I still think I want to go with your second option. If someone said they want to distinguish between "1000" and "1e3" as JSON values, I'd tell them they're out of luck, but if there's any vaguely reasonable context in which it makes sense to distinguish between different JSON expressions (and the spec doesn't explicitly say they're equivalent), I want to support that.

from circe.

travisbrown avatar travisbrown commented on July 3, 2024

This is fixed in #189, which distinguishes positive and negative zero values as JSON numbers.

from circe.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.