Hacker News new | ask | show | jobs
by xscott 600 days ago
It's a rule, and it behaves like people probably expect for small numbers. But following that rule:

      float(0.5) +
      bigint(9007199254740993)
    == float(9007199254740992)
I wouldn't parade it around as a triumph over the problem, and it's arguably better to require people to be explicit about whether converting the float to bigint, or the bigint to float, is what you wanted.
1 comments

That doesn't really strike me as worse than any other use of == on a float. If anything needs to change there, I think it's more rigor in float comparisons.

Basically, ULP-level inaccuracy is a problem inherent to having float at all, even without bignum interactions. They would be a menace even if you had a pure tower from 32 bit int to double to complex to more.

I wasn't trying to draw attention to comparisons for equality. Perhaps I should've used an arrow => instead of == to indicate "the result of this operation", but that probably would've caused confusion too...

The real point is that you can get some non-intuitive answers from letting that numeric tower make conversion decisions for you. It's just a rule, and it's not an amazing rule.

> I wasn't trying to draw attention to comparisons for equality. Perhaps I should've used an arrow => instead

Then it's even less of issue. Yes if you convert to a float you get rounding, what did you expect when you introduced a float?

It's somewhat unintuitive but that's the nature of floating point.

> The real point is that you can get some non-intuitive answers from letting that numeric tower make conversion decisions for you. It's just a rule, and it's not an amazing rule.

But again, you can have the same kind of issue without bignums. It's not a tower problem it's a float problem.

I think I can summarize your point of view as, "any use of floats should be treated as undefined behavior, so you get what you deserve."

And that says nothing about whether implicit conversions are a good idea or not.

The specific type of conversion is one I don't see as a big issue. The programmer deliberately decided to use an imprecise data type for the calculation.

But more importantly, I'm saying that the problematic rounding can occur even if your tower does not have both bigint and float. It can happen even if every layer can completely represent every value of the layer above it. Do you have any complaints that are unique to a tower that has both bigint and float, and don't apply to towers that only have float?

To elaborate on that, an implicit cast directly from a single bigint to a single float won't happen with the rules in the wikipedia article. You'd have to do something like bigint+float, which can have horrible rounding errors, but those horrible rounding errors are also present in float+float.

And you can even have these problems without a tower. So I don't see how the bigint and float scenario is an argument against towers.

From a distance, I kind of like Scheme, so I went and re-read the R5RS section on the topic. To me, the numeric tower (generalized) says:

   N < Z < Q < R < C < H

   ℕ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ ⊂ ℍ
That's a nice statement about idealized sets of numeric values. So `integer?` implies `rational?` implies `real?` implies `complex?` implies `number?` in Scheme predicates and type conversions.

But no programming language can have "Reals" (they aren't computable), so floats are a common/useful approximation. And in actuality `bigint?` doesn't imply `floating?`, and `floating?` doesn't imply `bigint?`. Neither is a strict subset of the other, and because of this you can easily find examples where implicit conversion does something "questionable". You've made it about rounding errors, but I'm trying to criticize something about pretending they are subtypes/subsets. Claiming it's a tower and hand waving about exact/inexact doesn't make it a tower, and so I think implicit conversion for these is a poor choice.

You can have little subset relations for implicit conversions:

    float32?   implies  float64?
    float64?   implies  complex64?
    float32?   implies  complex32?
    complex32? implies  complex64?

    fixint?    implies  bigint?
    fixint?    implies  rational?
    bigint?    implies  rational?
Since this is supposedly in a discussion about JavaScript, maybe even:

    fixint?    implies  float64?
All of those relate true subsets for the collection of values they can represent, but it's not much of a tower. It's more a collection of DAGs.