Monday, April 13, 2009

Python float input validation

If you put 'nan' in as a string, a cast to float will not raise an exception.

I am not sure this is a good design, but the counterintuitive workaround is this.

To test if a Python float is not a number, see if it is equal to itself!
....val = float(raw_input("Air speed of an unladen swallow: "))
....print "foo"
if val != val
....print "foo also!"


John said...

This behavior results from the standard behavior of floating point numbers. According to the standard (IEEE 754), a NaN cannot equal anything, not even another NaN. In C, if x is of type double, then the statement (x == x) will evaluate to true if and only if x is a valid number, i.e. x is not a NaN.

Michael Tobis said...

I was surprised it could cast "nan", but I guess that is probably useful on second thought. Anyway the x != x thing made a strange sort of sense.

It seems to me there should just be an isfinite() predicate for floats, though.

I was testing my input field and just happened to use "nan" out of misguided whimsy; this wasn't caught and caused a non-local error I had to debug!

I bet there are thousands of science and engineering programs that cast from raw input without this check.

John said...

I'm sure you're right about code not doing these kinds of checks.

I have some C++ code IsNumber that just returns (x == x). It has comments explaining that despite all appearances, the code is correct. But I keep such obscure trickery strictly quarantined and only let IsNumber see the light of day in application code.

Infinites are different than NaNs. An infinite number does equal itself.

I've written about all this here.

Michael Tobis said...

Aargh. So I have to test for "inf" as well!