Why are floats so cursed? I ask that non-rhetorically. It's not only ye olde NaN!=NaN; like half of the virtual ink spilled on nailing down language semantics also ends up being about arcane float-related esoterica. Is this, e.g., somehow inherent to the problem space? A weird historical clusterfuck? Something else? (Most recently reminded by: github.com/rust-lang/unsafe-co)

@glaebhoerl my theory: floats are cursed because people want real numbers, but real numbers are tricky because actual constructible real numbers have a lot of undesirable properties, like the inability to determine digits. real numbers are a connected type, so the only functions from R to Bool that respect continuity are constant functions. so either we have analog computers, or we must work with approximations. and that leads to shenanigans.

@glaebhoerl and there are other ways to approximate reals, but floats are very economical... we can even do exact real arithmetic nowadays (where the approximation level is adjusted at the use site, unlike with floats where the approximation level is baked in) but it's expensive & high level...

@typeswitch The need to be approximate is indeed *part* of the cursedness (implying non-associativity too) and the part that seems most inescapable. But so much else seems unforced. NaN bit patterns, global mutable fenv, denormals, x87, NaN!=NaN of course, -0 == +0, and there's more I'm probably forgetting. Everything designed by humans has flaws, but why such a concentration.

@glaebhoerl

looking into it, it seems that the design of FP follows mostly from the need for operations to be closed.

NaN is good, actually -- it says "you did something wrong" rather than just giving you a wrong value.

global mutable fenv (& x87 state) is just an ABI issue tho? it's global state, so it's like everything else in these cursed machines -- e.g. registers are global state -- and the point of ABIs is for people to manage all that global state in a compatible way.

@glaebhoerl my biggest issue with the design is how division by zero sometimes gives you a positive or negative infinity, and it depends on the sign of the zero... that seems like a big mistake imo. i guess the idea is that the zeros might represent some kind of underflow, or maybe a loss of precision that has occurred because of arithmetic ... so that when you divide by that you get an overflow representation.

but that's messy ... division by zero should just be NaN imo.

@typeswitch I think the idea is -- since it's all approximate anyways -- to conflate zero with infinitesimal. Which makes some sense, in the same kind of way that NaN!=NaN makes sense because conceptually NaNs are not any particular known value. But violating reflexivity and congruence of equality are both bad.

@typeswitch I didn't say NaN is bad (by "bit patterns" I mean that there are very many possible NaN representations and this leads to portability/determinism headaches)

Re fenv, see that whole thread I linked... (I agree with github.com/rust-lang/unsafe-co, resp. to the extent possible, all this stuff should be specified by immediates on the instruction itself)

Sign in to participate in the conversation
Mastodon

a Schelling point for those who seek one