News for hackers. Stuff that matters.
Re:John Gustafson’s crusade to replace floating point with s... by dragontamer on Tuesday July 09, 2019 @01:04AM (#20389152)
Yes and no.

1. Yes -- On old x86 systems, the x87 registers were 80-bits and the bottom bits were undefined. You could theoretically have a 1-bit difference on some results depending on what the bottom 26 bits (that were undefined, because you had 64-bit floats most of the time, even though the machine did things 80-bits at a time).

2. No -- Modern x86 systems use SSE registers, which are 64-bits. There are a whole slew of configuration options, but if Windows / Linux does their job, you should have the same rounding-errors across your program (unless you manually change the rounding options, but that's your own fault if you go that route).

3. Kinda yes -- Floating point operations are NON-associative. (A+B)+C does NOT equal A+(B+C). The best example is Python:

>>> (1+1)+2.053 9007199254740994.0 >>> 1+(1+2.053) 9007199254740992.0

253 is the first value which starts to "round off" 1.0 in double-precision. So (1+2.053) == 2.053, because the value was rounded off.

Due to #3, even if you did everything correctly (ie: set the rounding flags so they were consistent), if your arithmetic happened in slightly different orders (very common in network-games, where different players may have their updates in slightly different orders), you end up with a 1-bit error between clients... which completely borks your simulation.

Because #3 is nonintuitive, many people think that you get different results when using floats. But its simply due to non-associativity.

Re:John Gustafson’s crusade to replace floating point with s... by deathanatos on Tuesday July 09, 2019 @01:11AM (#20389170)
In case you're like me, reading this comment and thinking "how the heck is 1 plus 1 plus 2-ish like 90 gazillion?", it's:

  >>> (1+1)+2.0**53
  9007199254740994.0
  >>> 1+(1+2.0**53)
  9007199254740992.0
The exponent operator (double star) got transformed into italics apparently.
Re:John Gustafson’s crusade to replace floating point with s... by pure-awesome on Tuesday July 09, 2019 @03:21AM (#20389642)
Oh! Thank you! The comment makes a lot more sense now!

The newlines also helped, by the way, because I was wondering what putting the two numbers next to each other was meant to indicate.

Re:John Gustafson’s crusade to replace floating point with s... by martinpw on Tuesday July 09, 2019 @01:19AM (#20389200)
> On old x86 systems, the x87 registers were 80-bits and the bottom bits were undefined. You could theoretically have a 1-bit difference on some results

I spent a long time once debugging an issue arising from this. Code was basically:

  double x = y;
  [...]
  if (x>y) fail;
Nothing in between the assignment and the check changed the value of x or y, yet the check triggered the fail condition. Turned out to be that one of the value stayed in the 80 bit x87 register and one was written to RAM as a 64 bit value, then loaded back into an x87 register for the check, resulting in the inequality. Running in a debugger wrote both values out of the registers before the check, making the problem unreproducible.
Re:John Gustafson’s crusade to replace floating point with s... by desdiv on Tuesday July 09, 2019 @02:19AM (#20389408)
Yes, that's a hard bug to catch, but if the mantra of "every floating point comparison must use a context-appropriate epsilon" is followed, then it wouldn't have happened in the first place.
Re:John Gustafson’s crusade to replace floating point with s... by stkdump on Tuesday July 09, 2019 @08:00AM (#20390910)
I hate that mantra, as it produced more bugs and inaccuracies in the code I have to work with than necessary. Actually you should be able to rely on the equality of a value with its copy no matter what. We are past the FPU days, so I think we can let go of these mindless epsilons sprinkled over the code.

(Even during the FPU days, every ; should have rounded each value to the size of the variables, unless you use a special compiler switch to make FP math faster)

Re:John Gustafson’s crusade to replace floating point with s... by martinpw on Tuesday July 09, 2019 @02:32AM (#20389455)
Absolutely, and the fix involved adding a tolerance check. Not my code, I was the new guy at the time, and my job was trying to fix the bugs nobody else wanted to deal with...
Re:John Gustafson’s crusade to replace floating point with s... by pvg on Tuesday July 09, 2019 @01:51AM (#20389296)
Nothing in between the assignment and the check changed the value of x or y

What was the check for?

Re:John Gustafson’s crusade to replace floating point with s... by martinpw on Tuesday July 09, 2019 @02:31AM (#20389449)
There was code in between that could have changed the value, but it was never triggered in the bug case.
Re:John Gustafson’s crusade to replace floating point with s... by pvg on Tuesday July 09, 2019 @03:47AM (#20389740)
Ah yeah, that makes sense. Relying on FP equality should always make one's eye twitch a little but this is a neat way of hiding it.
Re:John Gustafson’s crusade to replace floating point with s... by rxhernandez on Tuesday July 09, 2019 @03:51AM (#20389763)
Wrt #3, I've had huge errors (I think on the order of 10e-3) in non linear curve fitting spectroscopy algorithms because of this. One of the physics research fellows in the group looked at me like I was an idiot for not knowing the order of multiplication mattered (I still have no clue why he would think it's a standard thing to know this).
Re:John Gustafson’s crusade to replace floating point with s... by roel_v on Tuesday July 09, 2019 @04:09AM (#20389821)
Lots of researchers cargo cult floating point programming. I had a Fortran program a few months ago where the author did "if var > 0.99 and var < 1.01 then" etc., where "var" was an integer. I tried to search back where and how that was ever done, but no scenario made any sense ("var" was a categorical variable and always had been). So I went back to some of the original authors and there too they looked at me like I was an idiot and said "you should never test for equality, always check for distance within a certain epsilon". So I asked about the difference between integers and floating point and then they "didn't have time for technical details in code written 10 years ago." Shrug, they pay me to fix that particular sort of weirdness I guess.
Re:John Gustafson’s crusade to replace floating point with s... by OskarS on Tuesday July 09, 2019 @06:38AM (#20390459)
In all likelyhood, the reason that's there isn't because a programmer was an idiot. Almost certainly, that variable was originally a float, then some time later another programmer came in and refactored it into an int, but missed fixing this condition, since it technically "works" for ints as well.

This is a good argument for stricter typechecking than anything else. In Rust, a condition like that wouldn't compile because of the mixed types. That's probably a good call in my opinion: it alerts the programmer that there's something funky going on, and it forces the programmer to be explicit about how the comparison should actually happen.

I do find myself doing the "cargo cult" thing from time to time. I was working on a codebase where Lua was embedded in C++, and there were all these flags that had to work in both systems. Because Lua only supports 64-bit floats as a numeric type, the natural type for these were doubles, and "by convention" they only ever had the values 0.0 or 1.0. It was a bit silly of me, but everytime i saw the line `if (fSomeFlag == 1.0f) ...` in the code, I would wince. It just feels wrong to do that to floats. I found myself regularly writing `if (fSomeFlag > 0.5f) ...` instead.

Of course, I was wrong about this. These weren't values determined as a result of arithmetic, they were always set to whole numbers. There was never going to be a case where the actual value of the flag would be 0.9999998f or whatever. But still: once you've been burned by the "floating point equality comparison", you live in fear of it forever after.

Re:John Gustafson’s crusade to replace floating point with s... by roel_v on Tuesday July 09, 2019 @09:32AM (#20391506)
It was the same in the situation I was talking about; all numbers that would always be integers because of their nature (and in the data source they came from, they were integers, there was no way this could ever have been floating point, or that the values ever had any non-0 digits after the comma). And well, they probably weren't 'idiots' in the absolute sense, in fact I'm 100% sure that they are much smarter (and/or just plain better humans in other ways) than I am in many respects.

My point was that many researchers can only cobble together somewhat barely working software by taking snippets from their undergraduate textbooks (or googling/stack overflowing, for those under 40), and have no idea about many/most of the underlying principles. If only they would recognize that, and leave the software development to professionals, instead of treating it as an inconsequential implementation detail that is beneath them. Then again, if they did, they wouldn't have to pay me what they do to fix it up afterwards. So meh?

Re:John Gustafson’s crusade to replace floating point with s... by it_aint_that on Tuesday July 09, 2019 @01:30AM (#20389236)
x87 has been functionally superseded (largely by various SSE iterations), but it is still supported for backwards-compatibility.

Modern applications and compilers largely do not use x87, but they can, and x87 results depending on hidden bits persists in modern x86_64 CPUs.

Re:John Gustafson’s crusade to replace floating point with s... by Zardoz84 on Tuesday July 09, 2019 @04:25AM (#20389881)
DLang allow to use it explicitly by using Real type, I instead of Double and Float types.
Re:John Gustafson’s crusade to replace floating point with s... by enriquto on Tuesday July 09, 2019 @04:00AM (#20389790)
yet it is still used for arithmetic with "long double"
Re:John Gustafson’s crusade to replace floating point with s... by josefx on Wednesday July 10, 2019 @01:58AM (#20399479)
Wouldn't that resovle the issue? long double contains the whole 80 bit state, not much space for undefined bits left.
Re:John Gustafson’s crusade to replace floating point with s... by enriquto on Wednesday July 10, 2019 @04:31AM (#20400165)
Yes, it resolves the issue in practice. However, the issue is an implementation detail of the compiler, not of the floating point format itself.
Re:John Gustafson’s crusade to replace floating point with s... by fluffything on Tuesday July 09, 2019 @06:51AM (#20390536)
> . No -- Modern x86 systems use SSE registers, which are 64-bits. There are a whole slew of configuration options, but if Windows / Linux does their job, you should have the same rounding-errors across your program

Knock, knock. Who is there? Floating-point contraction.

Re:John Gustafson’s crusade to replace floating point with s... by DubiousPusher on Tuesday July 09, 2019 @02:51AM (#20389540)
> Modern x86 systems use SSE registers

Are your sure of this? It's my understanding that SSE registers require the use of a special API and standard floating point operations do not use them.

But the last time I worked with them was writing a SIMD vector library 7 years ago.

Re:John Gustafson’s crusade to replace floating point with s... by Tuna-Fish on Tuesday July 09, 2019 @05:27AM (#20390147)
64-bit x86 CPUs are defined to support SSE2 as a minimum, and all 64-bit operating systems use it by default.

For 32-bit systems, you still theoretically have to check, but I think every halfway modern compiler also uses SSE2 as the default target.

Re:John Gustafson’s crusade to replace floating point with s... by titzer on Tuesday July 09, 2019 @03:52AM (#20389766)
> It's my understanding that SSE registers require the use of a special API and standard floating point operations do not use them.

No, SSE registers are used by most compilers that do floating point these days. They support all the usual IEEE float math operations and a host of bit twiddling operations as well as vector operations. The vector operations do still require using compiler intrinsics in C++, although some autovectorization does occur in gcc, icc, and llvm.

Re:John Gustafson’s crusade to replace floating point with s... by DubiousPusher on Tuesday July 09, 2019 @01:03PM (#20394007)
Ah yes. This is what I was remembering. For vector operations you have to use special intrinsics
Re:John Gustafson’s crusade to replace floating point with s... by hrydgard on Tuesday July 09, 2019 @02:59AM (#20389567)
Compilers now exclusively target the SSE registers (with scalar SSE instructions like mulss), and they did 7 years ago too.
Re:John Gustafson’s crusade to replace floating point with s... by account42 on Tuesday July 09, 2019 @07:08AM (#20390625)
https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html

  -mfpmath=unit
  
      Generate floating-point arithmetic for selected unit unit. The choices for unit are:
  
      ‘387’
  
          Use the standard 387 floating-point coprocessor present on the majority of chips and emulated otherwise. Code compiled with this option runs almost everywhere. The temporary results are computed in 80-bit precision instead of the precision specified by the type, resulting in slightly different results compared to most of other chips. See -ffloat-store for more detailed description.
  
          This is the default choice for non-Darwin x86-32 targets.
Re:John Gustafson’s crusade to replace floating point with s... by berkut on Tuesday July 09, 2019 @03:02AM (#20389577)
I'm pretty certain all 64-bit x86 (so amd64) systems support SSE 2, so FP calcs are done with these registers.
Re:John Gustafson’s crusade to replace floating point with s... by epr on Tuesday July 09, 2019 @09:44AM (#20391628)
Common Lisp over here like:

  * (+ (+ 1 1) (expt 2 256))
  115792089237316195423570985008687907853269984665640564039457584007913129639938

  * (+ 1 (+ 1 (expt 2 256)))
  115792089237316195423570985008687907853269984665640564039457584007913129639938
Re:John Gustafson’s crusade to replace floating point with s... by deathanatos on Wednesday July 10, 2019 @05:59PM (#20407050)
Python will happily do this too, if you remove the ".0" in the example, the values become integers, instead of floats, and the computation is precise.

The point is to demonstrate a property of IEEE floats, not the language. I'd expect CL has some means of using IEEE floats too, and with the appropriate syntax, the same issues could be demonstrated.

Re:John Gustafson’s crusade to replace floating point with s... by FabHK on Tuesday July 09, 2019 @10:25AM (#20392035)
Many languages support BigFloats and BigInts, but this discussion is about IEEE 754 floats vs Gustavson's proposals.