22 comments

[ 3.0 ms ] story [ 40.5 ms ] thread
It is a shame we tend to teach floats as the computer version of reals. Thinking of them as "scientific numbers" really helps a ton with this.
True, but we also have to be careful about teaching ints as the computer version of integers.
Are they even reals? Math classes were a while ago at this point, but I'm fairly convinced they're just rationals. Not trying to be pedantic, just wondering.
Fair, I was largely riffing off the theme in the post. That is, I took it as an implicit idea that floats represent real numbers.

That said, I'd argue that they are neither reals nor rationals. They are scientific numbers with no syntax to indicate "repeated" tails. Would be like saying that you want someone to represent 1/3 using 6 digits with no bar notation. Best you can do is "0.33333" and that just isn't the same. Moving it so that you have 6 digits with 2 being exponent, you are stuck with "3.333e-01". Which is just different still.

The pitfalls of floats were taught when I was a college math major. That was in the mid 80s.
Isn’t the `real` datatype in Fortran a float64? Or am I making that up?
... but people are in the habit of using doubles. Many languages, like Javascript, only support doubles and int32(s) do embed in doubles.

I have some notes for a fantasy computer which is maybe what would have happened if Chinese people [1] evolved something like the PDP-10 [2] Initially I was wanting a 24-bit wordsize [3] but decided on 48-bit [4] because you can fit 48 bits into a double for a Javascript implementation.

[1] There are instructions to scan UTF-8 characters and the display system supports double-wide bitmap characters that are split into halves that are indexed with 24-bit ints.

[2] It's a load-store architecture but there are instructions to fetch and write 0<n<48 bits out of a word even overlapping two words, which makes [1] possible; maybe that write part is a little unphysical

[3] I can't get over how a possible 24-bit generation didn't quite materialize in the 1980s, and find the eZ80 evokes a kind of nostalgia for an alternate history

[4] In the backstory, it started with a 24-bit address space like the 360 but got extended to have "wide pointers" qualified by an address space identifier (instead of the paging-oriented architecture the industry) really took as well as "deep pointers" which specify a bitmap, 48-bit is enough for a pointer to be deep and wide and have some tag bits. Address spaces can merge together contiguously or not depending on what you put in the address space table.

"I can't get over how a possible 24-bit generation didn't quite materialize in the 1980s, and find the eZ80 evokes a kind of nostalgia for an alternate history"

Well... it depends on how you look at it.

While the marketers tried to cleanly delineate generations into 8- and 16- and 32-bit eras, the reality was always messier. What exactly the "bits" were that were being measureds was not consistent. The size of a machine word in the CPU was most common, and perhaps in some sense objectively the cleanest, but the number of bits of the memory bus started to sneak in at times (like the "64 bit" Atari Jaguar with the 32-bit CPU because one particular component was 64 bits wide). In reality the progress was always more incremental and there are some 24-bit things, like, the 286 can use 24 bits to access memory, and a lot of "32 bit graphics" is really 24 bits because 8 bits for RGB gets you to 24 bits. The lack of a "24-bit generation" is arguably more about the marketing rhetoric than the lack of things that were indeed based around 24 bits in some way.

Even today our "64-bit CPUs" are a lot messier than meets the eye. As far as I know, they can't actually address 64 bits of RAM, there are some reserved higher bits, and depending on which extensions you have, modern CPUs may be able to chew on up to 512 bits at a time with a single instruction, and I could well believe someone snuck something that can chew on 1024 bits without me noticing.

In the world of mainframes and minicomputers there were several 36bit machines. They were chosen because you could pack 6x6bit char codes into one word. Yes, back then ASCII was entirely just the uppercase subset. Off hand I can't recall exactly how EBCDIC and 80 col card codes were mapped.
This should be obvious. There are the same number of 32-bit integers as 32-bit floats [0], so for every float that is not an int, there exists an int that is not a float. Clearly most floats cannot be represented as integers, so the converse must be true as well.

But I still see people building systems where implicit conversation of float to int is not allowed because "it would lose precision", but that allow int to float.

[0] don't reply to me about NaNs, please

Something I found really annoying in the Avro spec is that they automatically convert between ints/longs and floats/doubles in their backwards compatibility system. That just seemed like an unforced error to me. (Maybe it's changed in newer versions of the standard?)
https://gist.github.com/deckar01/f77d98550eaf5d9b3a954eb0343...

Here is a visualization I made recently on the density of float32. It seems that float32 is basically just PCM, which was a lossy audio compression exploiting the fact that human hearing has logarithmic sensitivity. I’m not sure why they needed the mantissa though. If you give all 31 bits to the exponent, then normalize it to +/-2^7, you get a continuous version of the same function.

Well yes. Given N bits:

- Most floats are not ints.

- There are the same number of floats as ints.

- Therefore, most ints are not floats.

This is a fairly obvious one? Although I've mainly encountered the effect with long to double conversion.

On the other hand, floating point is the gift that never stops giving.

A recent wtf I encountered was partly caused by the silent/automatic conversion/casting from a float to double. Nearly all C-style languages do this even though it's unsafe in its own way. Kinda obvious to me now and when I state it like this (using C-style syntax), it looks trivial but: (double) 0.3f is not equal to 0.3d

The wtfness of it was mostly caused by other factors (involving overloaded method/functions and parsing user input) but I realized that I had never really thought about this case before - probably because floats are less common than doubles in general - and without thinking about it, sort of assumed it should be similar to int to long conversion for example (which is safe).

(comment deleted)
I'll take the contrary position and argue that most ints are floats, because ints are not uniformly distributed. 0, 1, 10, etc. are far more common.
I have been writing software for decades in areas ranging from industrial control to large business systems. I almost never use floats or doubles. In almost all cases 32 bit integers (and sometimes U64int) with some scaling suffices.

Perhaps it is the FORTRAN overhang of engineering education that predisposes folks to using floats when Int32/64 would be fine.

I shudder as to why in JavaScript they made Number a float/double instead of an integer. I constantly struggle to coerce JS to work with integers.

True but misleading. Like one of the other commenters also mentioned, most integers are small. For 32-bit you might run into integers above 2^23 bits once in a while, but for 64-bits it’s really not that common to have integers above 2^53, unless it’s a bit pattern instead of a natural number. So you could reasonably say “most integers _are_ 64-bit floats.”
A little known fact is that some intel processors use 80 bit registers to store double values, which can result in programs behaving differently based on the optimization level, because if values are stored in memory, like when building for debug, they are rounded.
But all int32 can be exactly represented by float64, which luajit uses extensively.