Live data from Hacker News

What even is a JSON number?

blog.trl.sn

91–100 of 151 posts

Re: What even is a JSON number?

#91
post #68
post #54

Earlier quoted context omitted.

I was attempting to solve this very problem in the Rust BigDecimal crate this weekend. Is it better to just let it crash with an out of memory error, or have a compile-time constant limit (I was thinking ~8 billion digits) and panic if any operation would exceed that limit with a more specific error-message (does that mean it's no longer arbitrary-precision?). Or keep some kind of overflow-state/nan, but then the com…

I think Haskell's warning-in-the-doc approach is not strong enough. I'd be in favor of distinguishing small and huge values using the type system. Have a Rust enum that contains either a small-ish number (the absolute value being 10^100 or less, but the threshold should be configurable preferably as a type parameter) or a huge number. Then the user will be required to handle it. Most of the time the user does not wan…

That seems to be the sentiment here. I'll take it into consideration. Thanks.

Re: What even is a JSON number?

#92
post #20
post #15

Earlier quoted context omitted.

That's true for every floating point number in every programming language you have ever used, though. $ python3 Python 3.10.13 (main, Aug 24 2023, 12:59:26) [GCC 12.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> 100000.000000000017 100000.00000000001

This is why Decimal exists: Python 3.8.10 (default, Nov 22 2023, 10:22:35) [GCC 9.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from decimal import Decimal >>> Decimal('100000.000000000017') Decimal('100000.000000000017') For example: >>> import json >>> json.loads('{"a": 100000.000000000017}') {'a': 100000.00000000001} >>> json.loads('{"a": 100000.000000000017}', parse_floa…

Decimal is not arbitrary precision, though. It has many of the same issues, you'll just see them in different places.

  >>> Decimal('100000.00000000000000000000017') + Decimal('1')
  Decimal('100001.0000000000000000000002')

Re: What even is a JSON number?

#93
post #51

Earlier quoted context omitted.

If you're going to extend Go the courtesy of customizing the parser, oughtn't you do the same for Python (and all the languages)? To wit, Python's json module has `parse_float` and `parse_int` hooks: https://docs.python.org/3/library/json.html#encoders-and-dec... Example: >>> json.loads('{"int":12345,"float":123.45}', parse_int=str, parse_float=str) {'int': '12345', 'float': '123.45'} FWIW, when I've cared about inte…

I'm just a JS guy trying to understand the world around me and documenting what I find, not trying to be discourteous (or even courteous). I'll add the note about Python, thanks for calling it out. FWIW JS does not have a similar capability so I can't add a note there.

> FWIW JS does not have a similar capability so I can't add a note there

This example on MDN seems to indicate that you can, am I misunderstanding it?

  const bigJSON = '{"gross_gdp": 12345678901234567890}';
  const bigObj = JSON.parse(bigJSON, (key, value, context) => {
    if (key === "gross_gdp") {
      // Ignore the value because it has already lost precision
      return BigInt(context.source);
    }
    return value;
  });
[0]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Re: What even is a JSON number?

#94
post #77
post #74

Earlier quoted context omitted.

IEEE 754 can represent integers larger than MAX_SAFE_INTEGER, just not all of them: https://en.wikipedia.org/wiki/Double-precision_floating-poin... That's still going to be a greater than 0.1% chance of hitting a non-representable value though.

It’s been a long long time. I may be remembering the ratio wrong, or we might have been clipping the range a bit.

> or we might have been clipping the range a bit

Well it's a pretty abrupt change. 53 bits work fine, at 54 bits a quarter of numbers get truncated, at 55 it's half.

Re: What even is a JSON number?

#95
post #65

Earlier quoted context omitted.

Until you want faster joins, in which case, comparisons of integers tend to be much faster on hardware I am aware of than string comparisons.

We're talking about deserialising JSONs in the application server here, nobody stops you from treating ids as numbers on the database side of things. But also, this sounds like a premature optimisation. Most applications will never reach a level where their performance is actually impacted by string comparison, and when you reach that stage, you're likely have already thrown out a lot of other common sense stuff like…

> when you reach that stage, you're likely have already thrown out a lot of other common sense stuff like db normalisation to get there

Don't most databases set a length limit on ID strings?

If you're setting a length limit, and it's made out of digits with no leading zeroes, then you might as well store it as a number. Is there a downside?

Re: What even is a JSON number?

#96

When I wrote my jsonptr tool a few years ago, I noticed that some JSON libraries (in both C++ and Rust) don't even do "parse a string of decimal digits as a float64" properly. I don't mean that in the "0.3 isn't exactly representable; have 0.30000000000000004 instead" sense. I mean that rapidjson (C++) parsed the string "0.99999999999999999" as the number 1.0000000000000003. Apart from just looking weird, it's a diff…

this requires multiple precision to do properly and isn't useful most of the time. its odd to describe this as "not properly". you might say "with exact rounding", but that makes it clearer that this isn't that useful a feature, especially since we usually expect floats to be inexact in the first place.

Rounding by more than an ULP is pretty bad. I don't think it's odd at all to describe rapidjson's behavior as improper.

At least 122.416294033786585 is between ...888 and ...889, though it's much closer to the former.

Re: What even is a JSON number?

#97

Long story short: don't use JSON numbers to represent money or monetary rates. Always use decimals encoded as string. It's surprising how many APIs fall short of this basic bar.

Depends on the language. On the JVM you are fine. With Javascript, doing math on big numbers is probably going to end in tears unless you know what you are doing. Either way, have some tests for this and make sure your code is doing what you expect.

Encoding numbers as string because you are using a language and parser that can't deal with numbers properly (even 64 bit doubles), is a bit of a hack. Basically the rest of the world giving up because Javascript can't get its shit together is not a great plan.

Re: What even is a JSON number?

#98

Earlier quoted context omitted.

I've been burned by a similar issue too. Lesson here is never to use numbers for things you are not planning to do math on. Ids should always be strings.

Isn't the lesson only that ids shouldn't be floats ? If they were integers everything would be fine, but JS numbers aren't integers, even if they look like them sometimes.

Nah, the lesson is broader than that, cause numbers as IDs have a whole bunch of problems and this is just one of them. Eg Twitter has incrementing number IDs and back when they had this whole ecosystem of 3rd party twitter apps (that they have since ruined), half the apps failed when the IDs became too large to fit into a 32-bit int.

If it looks like a number, and it quacks like a number, sooner or later people are going to treat it like a number.

Re: What even is a JSON number?

#99
post #54
post #28

I'll add that for Haskell, the library everyone uses for JSON parses numbers into Scientific types with almost unlimited size and precision. I say almost unlimited because they use a decimal coefficient-and-exponent representation where the exponent is a 64-bit integer. The documentation is quite paranoid that if you are dealing with untrusted inputs, you could parse two JSON numbers from the untrusted source fine an…

I was attempting to solve this very problem in the Rust BigDecimal crate this weekend. Is it better to just let it crash with an out of memory error, or have a compile-time constant limit (I was thinking ~8 billion digits) and panic if any operation would exceed that limit with a more specific error-message (does that mean it's no longer arbitrary-precision?). Or keep some kind of overflow-state/nan, but then the com…

I don't think there is any "sensible limit" which is big enough for everyone's needs, but low enough you won't blow out memory.

An 8 billion digit number is 2.5G? (Did I do my maths right?) All I need to do is shove 1,000 of those in a JSON array, and I'll cause an out-of-memory anyway.

On the other hand, any limit low enough that I can't blow up memory by making an array of 100K or so is going to be too low for some people (including me, I often make numbers of low-million numbers of digits).

Providing some method of putting a limit on seems sensible, but maybe just make a LimitedBigDecimal type, so then through the whole program there is a limit on how much memory BigDecimals can take up? (I haven't looked at the library in detail, sorry).

Re: What even is a JSON number?

#100
post #65

Earlier quoted context omitted.

I've been burned by a similar issue too. Lesson here is never to use numbers for things you are not planning to do math on. Ids should always be strings.

Until you want faster joins, in which case, comparisons of integers tend to be much faster on hardware I am aware of than string comparisons.

UUIDs are great for this. It’s really just a random 128-bit integer, which makes comparisons about as fast as variable-length integers on modern hardware. And they decode to strings which means no application code or API end-user code is going to assume it’s a number.
Post reply on HN