Floating point considered harmful

bool foo() {
  float a = 0.6;
  float b = 6.0;
  return (a == (b * 0.1));
}

bool bar(float c) {
  return (c != c);
}

When I learned coding on the C64, the two main tools where Basic, and direct memory access. Any advanced stuff was done in assembly. So basically, coding involved pretty much only pointer arithmetics and goto statements. Of course this was a long time ago and such constructs are now shunned, and many newer languages even prevent the code from doing such thing, which is probably a change for the better.

Strangely, there is one type of operations that is very dangerous, but which most languages do not restrict: floating point operations. Consider the snippet on the side, will foo return true? Maybe, but there is no guarantee that the bit representations of a and b will be equal. Will bar ever return true? Yes if c is NaN. Generally speaking, comparing bit for bit two floating points is a bad idea, and providing that operation to the programmer is a disservice. Floating point semantics are complicated, and only partially visible in the programming language: rounding, extended precision are typically not accessible.

A lot of the code I have seen just happily assumes that floats basically behave like integers, why would it not? Floating point numbers are the only types which in each and every language are allowed to have the same operators as integer. In most of the cases, using a fixed point (currencies) or fractional representation (computing averages and such) would be more appropriate, but such constructs are typically missing in the language, or are second class citizens – Python for instance only had fractions since version 2.6 and there is no shorthand notation to create them.

The only languages I used which had put some serious thoughts in their numerical representations where Ada and Smalltalk. The others seem to be happy to just clone C operations.

3 thoughts on “Floating point considered harmful

  1. I never really tried the NUMBER(n,m) type in Oracle, where n and m give the precision of the float.

    Better: introduce a new = operator (by default for float) where the precision is asked for : n and m are equal if |n-m| < ε (ε is compulsory). Should be probably more complex for very big and very small numers (how to compare 6,02.10^23 and 6,0200…001.10^23 ?)

  2. Actually, the computer can compute the ε itself: it knows the minimal increment for the precision of n and m.

Leave a Reply