TIP 520: Make NaN Quiet

Login
Bounty program for improvements to Tcl and certain Tcl packages.
Author:		Kevin B. Kenny <kevin.b.kenny@gmail.com>
State:		Draft
Type:		Project
Vote:		Pending
Created:	18 October 2018
Post-History:
Tcl-Version:	8.7
Keywords:	Tcl, floating point, NaN, not a number
Tcl-Branch:	tip-520

Abstract

This TIP proposes that the special floating point constants NaN, ±NaN, and [±]NaN(hex) be accepted in any context where other floating point constants may appear. This change has the effect of changing Tcl from 'signalling NaN' semantics (where floating-point exceptions are errors) to 'quiet NaN' semantics (where floating-point exceptions return the constant, NaN, and operations where one of the operands is NaN propagate the NaN to their results).

Background

Since Tcl 8.5, [TIP 132] Tcl has had the capability to recognize the special IEEE floating point constants, Inf (representing an infinity or an overflow) and NaN (representing a value that is 'Not a Number', ordinarily the result of some sort of floating point exception). Infinities are now accepted on an equal footing with other floating point constants; they can be passed anywhere that such a constant can appear, and they follow IEEE 754 rules for arithmetic.

The constant, NaN is different. If a floating-point expression yields a NaN, or if Tcl_GetDoubleFromObj receives such a constant, the system treats the condition as an error, 'domain error: argument not in valid range'.

This behaviour was specified explicitly in paragraph 5 of TIP 132:

The input and output conversions shall allow for the IEEE special values +Inf, -Inf, and NaN (and for denormalized numbers). The [expr] command shall be changed to allow +Inf and -Inf as the result of an expression; NaN shall still cause an error. Tcl_GetDoubleFromObj shall treat +Inf and -Inf as it does any ordinary floating point number, and return an error for NaN.

This sort of handling was adopted because at the time, NaN was a relatively new thing, and programmers were suspicious of it. Many believed that if operations like 0./0. or asin(2.0) were allowed to return NaN rather than throwing an immediate error, debugging would be greatly complicated, to very little benefit. (The personal recollection of the author of this TIP was that even infinities were tough to sell, for much the same reason.)

Since then, NaN values have been much more broadly accepted. Most C compilers have quiet-NaN behaviour by default; a floating-point exception returns NaN rather than raising SIGFPE. The world seems to have accepted William Kahan's remarks:

My thesis is that exceptions are not errors unless they are handled badly. Exceptions are opportunities for extra computation.... An exception is an event for which any policy you choose in advance will subsequently be found disadvantageous for somebody who will then, for good reason, take exception to the policy.

This change in sentiment was underlined for the author of this TIP by the fact that in no fewer than three separate conversations at the 2018 Tcl/Tk Conference, he was approached with queries about NaN handling. An increasing number of users are dealing with external systems that use NaN to indicate a missing value in a data set, and need NaN to be passed in and out gracefully.

Proposal

Tcl's expression evaluator, and the functions in ::tcl::mathfunc and ::tcl::mathop, shall be changed to allow NaN values to be returned from floating-point expressions. (This change has already been available in the source code for a long time, and can be enabled by adding -DACCEPT_NAN to the compilation options.)

The math functions max and min shall be defined so that if any argument to the function is NaN, the output shall be NaN.

Functions requiring integers, functions coercing 'double' values to integers (int, wide, round, entier), and the isqrt function shall continue to throw errors when presented with NaN (there seems to be nothing sensible to do with these cases).

The C interface Tcl_GetDoubleFromObj shall be modified to accept NaN's without thowing errors.

The implementations of the lsort -real and lsearch -real commands shall be modified to continue to throw errors if a NaN is encountered in either the list or the search pattern. Since NaN is unordered with respect to any floating point constant, there is no correct behaviour for these commands when asked to sort a list containing one.

Reference Implementation

Most of the implementation has been in the code base for along time, albeit hidden, under the -DACCEPT_NAN compilation option.

A few changes (updates to the test suite to reflect the new default; update to Tcl_GetDoubleFromObj; changes to max and min) still need to be made; the link to the implementation branch will be added to this TIP.

Unresolved Concerns

The change to Tcl_GetDoubleFromObj, alone among the changes outlined in this proposal, may need to be delayed until Tcl 9. It introduces a subtle incompatibility in C code in that quiet NaN values can be returned to a caller that does not expect them. In particular, the author has not yet investigated whether Tk methods such as xview, yview, xscroll, and yscroll will survive such exceptional arguments without throwing SIGFPE. These are invalid arguments - the author is willing to accept almost any behaviour that does not render the UI unusable or abort the process, but we need to verify that .my.widget yview NaN does not invoke nasal daemons.

History