<p>So I've seen that many languages return a <code>NaN</code> value when calculating an indeterminate arithmetic expression (e.g. <code>0/0</code>). Other languages, like Python, throw an error (but Python still has a <code>NaN</code> value returned by <code>float('inf')-float('inf')</code>). What are the pros and cons of each approach to indeterminate arithmetic expressions?</p>
<p>This question is distinct from <a href="https://languagedesign.stackexchange.com/q/15/89">What are different ways of handling runtime errors?</a> as this question asks specifically about ways of handling indeterminate arithmetic expressions, as opposed to the language mechanism for runtime error handling in general. Plus, there is no mention of <code>NaN</code> in the other question.</p>

<error-handling><expressions><floating-point>
Pros and cons of throwing an error versus returning a NaN value
CC BY-SA 4.0
2023-05-24T10:01:19.267Z
@mousetail it does not. There are no answers talking about returning a `NaN` value vs throwing an error for undefined expressions.
The Empty String Photographer
CC BY-SA 4.0
2023-05-24T10:36:07.520Z
Returning NaN is just one example of a method to handle errors
mousetail 'he-him'
CC BY-SA 4.0
2023-05-25T06:42:17.760Z
@mousetail That other question is too broad to be useful, and focused on cases where the error/not-error is encoded separately from the real result. Exceptional floating point values are a distinctive case, among other reasons because the error/not-error information is almost always encoded together with the value, and there are semi-error cases like denormal numbers.
Gilles 'SO- stop being evil'
CC BY-SA 4.0
2023-05-25T08:16:45.993Z
This is ***NOT*** a duplicate, stop closing my question!
The Empty String Photographer
CC BY-SA 4.0
2023-05-25T11:14:59.220Z
FYI, `float('nan')` also returns the builtin 'NaN' in Python
SectorCorruptor
<p>Much of the performance cost associated with exceptions not comes from the need to test for the exceptional condition, but rather with the fact that actions which would otherwise be easily recognizable as having no side effects beyond yielding some kind of result, and thus having no side effects in cases where the result is ignored, must all be treated as having potential side effects.</p>
<p>Although a carefully designed approach using latching overflow flags with loosely defined semantics in some situations (e.g. including separate &quot;has an overflow definitely happened&quot; and &quot;has an overflow definitely not happened&quot; checks, where the former could be moved ahead of operations that might cause overflow but the latter could not) could probably offer better performance than NaNs, NaNs are probably the best approach among those that has been widely adopted for dealing with computations which are found to be erroneous.</p>

CC BY-SA 4.0
2023-08-17T18:08:05.227Z
2023-08-17T18:08:05.227Z
supercat
<h2>NaN as Null</h2>
<p>As other answers already mentioned, <code>NaN</code> is about performance with floating point numbers. And the thing with fp math, is that when you use it, you use a lot of it, and then fp math performance is paramount.</p>
<p>You can think of NaN as the equivalent of <code>float?</code> type, that is, nullable number, with <code>null</code> replacing a failed computation. Making every math fp operation accept and return a <code>float?</code> may sound like an overkill, but that is what effectively happens with IEEE-754 and NaN, as an arbitrary computation may accept and return NaNs.</p>
<p>You can lessen the aNaNoyances of NaN by making this <code>float?</code> aspect a little more explicit. For example, in all math contexts, the signature of arguments and returns are always <code>float?</code>, a null float internally represented as a <code>NaN</code>, and where you need to show or store a represented valid computation, you will need to declare or cast this usage as no null, no NaN, it is really a number with digits, <code>float</code>.</p>
<h2>Configurable division</h2>
<p>On <code>int</code>s, there is a lot of baggage, and on division in particular, a lot of rounding and <em>failure</em> modes. Instead of trying to convey them all in syntax, you may adopt a <a href="https://langdev.stackexchange.com/a/2059">configurable</a> approach.</p>

CC BY-SA 4.0
2023-08-16T14:32:28.570Z
2023-08-16T14:32:28.570Z
André L F S Bacci
<p>On a language level, considering NaN as error and throwing an exception is a massive issue if you want to implement a component that simply passes values. There, a NaN can be a well-defined input and working around such issues is very very time consuming.</p>

CC BY-SA 4.0
2023-08-16T15:56:25.063Z
2023-08-16T15:56:25.063Z
feldentm
<h3>The need to check for <code>NaN</code>s</h3>
<p><code>NaN</code>s are in fact rarely useful, and tend to indicate bad input or algorithm. Just passing this value along tends to lead to a knock-on error later where it'll be harder to see whence it originated. Or even worse, it'll not be detected at all, and will have unfortunate effects:
<a href="https://i.sstatic.net/uGIEP.png" rel="noreferrer"><img src="https://i.sstatic.net/uGIEP.png" alt="NaN in a GUI" /></a><a href="https://i.sstatic.net/ZBU7v.png" rel="noreferrer"><img src="https://i.sstatic.net/ZBU7v.png" alt="NaN in a GUI" /></a><a href="https://i.sstatic.net/SqbqP.png" rel="noreferrer"><img src="https://i.sstatic.net/SqbqP.png" alt="NaN in a GUI" /></a></p>

CC BY-SA 4.0
2023-05-25T13:08:12.677Z
2023-05-25T13:38:11.953Z
2023-05-25T13:38:11.953Z
Adám
CC BY-SA 4.0
2023-05-27T11:30:41.260Z
Seems like it would be kinda funny when that happens…
The Empty String Photographer
CC BY-SA 4.0
2023-06-28T12:14:43.007Z
One situation where NaN could be useful in my opinion is if you have a big array of numbers, and a few missing or corrupted numbers in that array. When you have calculations to apply to all numbers in the array, you may not want the whole program to crash, and all calculations being interrupted or thrown out, just because of a few wrong numbers in the array. Imagine all numbers in the array are theoretically guaranteed to be nonnegative, but a few of them are slightly negative because of rounding errors. When you compute `sqrt(x)` for all `x`, the negatives are going to end up `NaN`.
Stef
CC BY-SA 4.0
2023-07-04T08:03:33.250Z
@Stef I believe that would return a complex number in python.
The Empty String Photographer
CC BY-SA 4.0
2023-07-04T09:40:30.897Z
@PlaceReporter99 Not really: both `numpy.sqrt` and `pandas.Series.pow(1/2)` would respect the type of the values: if they are already `complex`, it will use complexes, but if they are float, it'll put a `nan` for negative values. As for python's standard library functions, there are `math.sqrt` and `cmath.sqrt`, where the former will raise ValueError and the latter will use complex numbers, but those can only be applied to one number at a time, not to a whole array.
Stef
CC BY-SA 4.0
2023-11-22T09:27:28.037Z
To be fair, this is more about UI libraries allowing the terrible practice of just slapping a `float` onto the screen. A UI application should format a number before rendering it (e.g. group thousands, localize decimal point/comma, handle thin non-breaking spaces for units, etc), and in languages where a `float` can be NaN, they should simply require providing a fallback string for those cases (i.e. treat it similar to how you'd have to format Haskell's `Maybe` or Rust's `Some`).
Lazar Ljubenović
CC BY-SA 4.0
2023-12-03T21:38:39.343Z
@Stef use `map`
The Empty String Photographer
<p>One main reason for signalling arithmetic errors by <code>NaN</code> is the importance of array operations in scientific computing.</p>
<p>Let's say you want to take the logarithm of each element in an array. The result is another array, in which some values are possible <code>NaN</code>. This result is well-defined and in particular independent of implementation choices such as the order of iterations for multidimensional arrays. Moreover, you can filter out the <code>NaN</code>s, which is often a reasonable way to handle errors.</p>
<p>If instead the first negative argument to the logarithm raised an exception, the application programmer would have to implement complex error handling code in order to get all the &quot;good&quot; values in the array.</p>
<p>Put differently, <code>NaN</code> error values maintain the abstraction of arithmetic on arrays, rather than exposing the lower-level implementation detail of looping over elements.</p>

CC BY-SA 4.0
2023-05-25T19:48:37.257Z
2023-05-25T19:48:37.257Z
khinsen
<p>IEEE-754 actually makes a number of affordances for different ways of handling erroneous conditions, most of which were sadly ignored or implemented poorly by programming languages; in short, <em>it should be up to the programmer to decide on an application-specific basis</em>, and adhering to what the standard actually says will get you there.</p>
<p>IEEE-754 specifies a number of <em>exceptions</em>.  An exception can be signalled after performing an arithmetic operation; for example, the division-by-zero exception will be signalled if you (shocker) divide a (nonzero) number by zero, and the invalid operation exception will be signalled if you add infinities of opposite sign.</p>
<p>When an exception is signalled, the default behaviour is to set a corresponding <em>status flag</em>, compute an alternate result to use instead, and resume execution.  For instance, following an invalid operation, you will get a nan, and following division by zero, you will get an infinity.</p>
<p>Already, we can see two different error-handling strategies.  We could check if some result is nan.  But we could also: clear all the status flags; perform some computation; check the value of the status flags.  If you see that the invalid operation status flag got set, then you know that you performed an invalid operation somewhere.</p>
<p>But IEEE-754 also specifies some alternate exception behaviours that an implementation can optionally support.  Two are of interest.  You could have the operation throw an error (if your language supports error-throwing and unwinding); this is the other error-handling strategy you suggest.  You could also specify some special code to be run when the exception is signalled, which would be able to examine the problematic operation and its arguments, and execute arbitrary code to compute an alternate result to be used instead (and continue operation).  This could be useful if, for example, <a href="https://www.jsoftware.com/papers/eem/0div0.htm" rel="nofollow noreferrer">you think that 0/0 should be 0</a>.</p>
<p>These two alternate exception-handling strategies could be unified into one if you support something like algebraic effect handlers or the common lisp condition system.</p>
<p>It is worth noting that, although x86 supports trapping exceptions, riscv does not, and on arm it is an optional feature implemented only by apple.  This makes it difficult to implement them performantly and portably.  One approach is as follows: execute a large chunk of straight-line math code with no side effects as-is, then check the status flags.  If a status flag got set that is associated with alternate exception-handling behaviour, then re-execute that code with special instrumentation checking for exceptions after each operation.</p>

CC BY-SA 4.0
2023-08-15T22:44:20.283Z
2023-08-15T23:43:24.617Z
2023-08-15T23:43:24.617Z
Moonchild
CC BY-SA 4.0
2023-08-15T23:55:16.030Z
IEEE-754 also defines a concept of "signalling" vs "quiet" NaNs -- a "signalling" NaN is basically throwing an exception that aborts the current compilation.  Support for signalling NaNs is optional, though.
Chris Dodd
CC BY-SA 4.0
2023-08-17T00:11:04.427Z
one thing to point out is that the lack of language is largely the fault of ieee and CPU designers. the modes are specified by global CPU flags rather than per operation which makes composing different modes in programs very hard to do well
Oscar Smith
CC BY-SA 4.0
2023-08-17T06:33:01.953Z
Explicit dataflow would be valuable, but I'm not asking the languages to support anything more than ieee-754 and the cpu architectures support.
Moonchild
<p>This doesn't apply to just division by zero.</p>
<p>First, a quick note on terminology. IEEE-754 distinguishes an <em>exception</em> from a <em>trap</em>. An exception is an event that may occur, and a trap is one possible response to that condition occurring.</p>
<p>The IEEE-754 standard defines five exceptions:</p>
<ul>
<li>Invalid operation: mathematically undefined (e.g. <span class="math-container">$\sqrt{-1}$</span>).</li>
<li>Division by zero: an operation on finite operands gives an exact infinite result. The 1985 revision only defined this for actual division by zero, but later revisions include things like <span class="math-container">$\log 0$</span>.</li>
<li>Overflow: a finite result is too large to be represented accurately.</li>
<li>Underflow: a result is so small that it is outside the normal range.</li>
<li>Inexact: the exact unrounded result is not representable exactly.</li>
</ul>
<p>The first three are called &quot;common exceptions&quot;, and usually can't be ignored when they occur. The last two, despite not being &quot;common&quot;, are in fact extremely common: almost all floating point operations &quot;raise&quot; those exceptions and they can usually be ignored. It's actually quite rare that (say) a division operation returns an exact result.</p>
<p>The IEEE-754 standard specifies that whether or not each kind of exception actually causes a trap can be separately controlled. If the exception's trap is enabled, and the exception occurs, then a platform-specific stuff trap occurs (e.g. <code>SIGFPE</code> on Unix). If the exception's trap is disabled, then a &quot;reasonable&quot; value is returned and a flag is set recording that the exception occurs.</p>
<p>The exact value returned depends on a bunch of factors:</p>
<ul>
<li>Invalid operation returns a quiet <code>NaN</code>.</li>
<li>Division by zero returns positive or negative <code>Inf</code>.</li>
<li>Overflow returns either <code>Inf</code>, or the representable number of largest magnitude, depending on the rounding mode.</li>
<li>Underflow returns a subnormal number or zero (which is technically just a kind of subnormal number), respecting the rounding mode.</li>
<li>Inexact returns a rounded value.</li>
</ul>
<p>When you raise a trap, there is then the question as to how this trap is reported. This is an especially important question for automatic vectorisation; suppose you have three parallel division operations that the compiler decides could be performed in a 4-way SIMD unit. Well that's nice, but if division by zero traps are turned on, you had better guarantee that the &quot;unused&quot; SIMD lane contains values that can't trap.</p>
<p>Some architectures, such as Cray-1 and Alpha AXP, made the design decision that, even when programmers want trapping arithmetic exceptions, it's a rare occurrence. Therefore, arithmetic exceptions don't necessarily need to trap in the precise location where they occurred in release code.</p>
<p>The Alpha has a &quot;trap barrier&quot; instruction <code>TRAPB</code> which checks the trap flags to see if a trap occurred and raise it if appropriate. For debug-mode compilation, the compiler might insert more <code>TRAPB</code> instructions than it would in a release-mode compilation. This decision makes for a much simpler superscalar CPU, and gives much better power performance, despite not being technically IEEE-754 compliant.</p>
<p>Note that this behaviour fits with the way that programming languages typically define trapping arithmetic handlers: a trap is raised by a high-level language concept such as a <em>statement</em> or a <em>block</em>, rather than a CPU instruction.</p>

CC BY-SA 4.0
2023-08-16T02:56:05.210Z
2023-08-16T15:02:46.857Z
2023-08-16T15:02:46.857Z
Pseudonym
CC BY-SA 4.0
2023-08-16T07:14:16.803Z
$\sqrt{-1}$ is actually the imaginary unit $i$.
The Empty String Photographer
CC BY-SA 4.0
2023-08-16T11:46:07.440Z
@TheEmptyStringPhotographer First off, in $\mathbb{C}$, there is no *principal* square root of $-1$. But more importantly, $i$ is not representable as a IEEE-754 floating point number. Introducing `+Inf`, `-Inf`, and `NaN` makes the floating point system algebraically closed without introducing complex numbers.
Pseudonym
<h1>Performance</h1>
<p>The <a href="https://en.wikipedia.org/wiki/IEEE_754" rel="noreferrer">IEEE 754 standard</a> for floating point numbers defines, for example, that <code>0 / 0</code> should be a NaN. Many FPUs nowadays directly implement IEEE 754 operations, and therefore checking for the special condition of division by zero before calling the float-division instruction is less performant. Of course, such a difference is marginal in a language like Python, and it can freely choose whether throwing or NaNs are the most correct result.</p>
<p>As an example, <a href="https://godbolt.org/z/T37e9of17" rel="noreferrer">this C++ code</a> compiles to using the <code>divsd</code> instruction directly.</p>

CC BY-SA 4.0
2023-05-24T10:01:55.023Z
2023-05-24T10:01:55.023Z
RubenVerg
CC BY-SA 4.0
2023-05-24T11:49:00.260Z
Of course this depends on the situation. If you have a function like `arr, x => arr.map(el => el/x)` and you call it with `x=0`, it may be far faster to throw on the first division, depending on the size of the array.
Bbrk24
CC BY-SA 4.0
2023-05-24T15:50:21.823Z
You have a point. Maybe some compiler optimization can be found, but surely there are some places where throwing might be faster.
RubenVerg
# Pros and cons of throwing an error versus returning a NaN value
Posted by: username_0 on 2023-05-24
So I've seen that many languages return a `NaN` value when calculating an indeterminate arithmetic expression (e.g. `0/0`). Other languages, like Python, throw an error (but Python still has a `NaN` value returned by `float('inf')-float('inf')`). What are the pros and cons of each approach to indeterminate arithmetic expressions?

This question is distinct from [What are different ways of handling runtime errors?](https://languagedesign.stackexchange.com/q/15/89) as this question asks specifically about ways of handling indeterminate arithmetic expressions, as opposed to the language mechanism for runtime error handling in general. Plus, there is no mention of `NaN` in the other question.
**Tags:** error-handling expressions floating-point
> **Comments:**
> **username_0**: @mousetail it does not. There are no answers talking about returning a `NaN` value vs throwing an error for undefined expressions.  
> **username_1**: Returning NaN is just one example of a method to handle errors  
> **username_2**: @mousetail That other question is too broad to be useful, and focused on cases where the error/not-error is encoded separately from the real result. Exceptional floating point values are a distinctive case, among other reasons because the error/not-error information is almost always encoded together with the value, and there are semi-error cases like denormal numbers.  
> **username_0**: This is ***NOT*** a duplicate, stop closing my question!  
> **username_3**: FYI, `float('nan')` also returns the builtin 'NaN' in Python  
---
## 8 answers
### Answer by username_7 on 2023-05-25. Score: 9
### The need to check for `NaN`s

`NaN`s are in fact rarely useful, and tend to indicate bad input or algorithm. Just passing this value along tends to lead to a knock-on error later where it'll be harder to see whence it originated. Or even worse, it'll not be detected at all, and will have unfortunate effects:
[![NaN in a GUI](https://i.sstatic.net/uGIEP.png)](https://i.sstatic.net/uGIEP.png)[![NaN in a GUI](https://i.sstatic.net/ZBU7v.png)](https://i.sstatic.net/ZBU7v.png)[![NaN in a GUI](https://i.sstatic.net/SqbqP.png)](https://i.sstatic.net/SqbqP.png)
> **Comments:**
> **username_0** (2023-05-27): Seems like it would be kinda funny when that happens…  
> **username_8** (2023-06-28): One situation where NaN could be useful in my opinion is if you have a big array of numbers, and a few missing or corrupted numbers in that array. When you have calculations to apply to all numbers in the array, you may not want the whole program to crash, and all calculations being interrupted or thrown out, just because of a few wrong numbers in the array. Imagine all numbers in the array are theoretically guaranteed to be nonnegative, but a few of them are slightly negative because of rounding errors. When you compute `sqrt(x)` for all `x`, the negatives are going to end up `NaN`.  
> **username_0** (2023-07-04): @Stef I believe that would return a complex number in python.  
> **username_8** (2023-07-04): @PlaceReporter99 Not really: both `numpy.sqrt` and `pandas.Series.pow(1/2)` would respect the type of the values: if they are already `complex`, it will use complexes, but if they are float, it'll put a `nan` for negative values. As for python's standard library functions, there are `math.sqrt` and `cmath.sqrt`, where the former will raise ValueError and the latter will use complex numbers, but those can only be applied to one number at a time, not to a whole array.  
> **username_9** (2023-11-22): To be fair, this is more about UI libraries allowing the terrible practice of just slapping a `float` onto the screen. A UI application should format a number before rendering it (e.g. group thousands, localize decimal point/comma, handle thin non-breaking spaces for units, etc), and in languages where a `float` can be NaN, they should simply require providing a fallback string for those cases (i.e. treat it similar to how you'd have to format Haskell's `Maybe` or Rust's `Some`).  
> **username_0** (2023-12-03): @Stef use `map`  
---
### Answer by username_15 on 2023-05-24. Score: 8
# Performance

The [IEEE 754 standard](https://en.wikipedia.org/wiki/IEEE_754) for floating point numbers defines, for example, that `0 / 0` should be a NaN. Many FPUs nowadays directly implement IEEE 754 operations, and therefore checking for the special condition of division by zero before calling the float-division instruction is less performant. Of course, such a difference is marginal in a language like Python, and it can freely choose whether throwing or NaNs are the most correct result.

As an example, [this C++ code](https://godbolt.org/z/T37e9of17) compiles to using the `divsd` instruction directly.
> **Comments:**
> **username_16** (2023-05-24): Of course this depends on the situation. If you have a function like `arr, x => arr.map(el => el/x)` and you call it with `x=0`, it may be far faster to throw on the first division, depending on the size of the array.  
> **username_15** (2023-05-24): You have a point. Maybe some compiler optimization can be found, but surely there are some places where throwing might be faster.  
---
### Answer by username_10 on 2023-05-25. Score: 6
One main reason for signalling arithmetic errors by `NaN` is the importance of array operations in scientific computing.

Let's say you want to take the logarithm of each element in an array. The result is another array, in which some values are possible `NaN`. This result is well-defined and in particular independent of implementation choices such as the order of iterations for multidimensional arrays. Moreover, you can filter out the `NaN`s, which is often a reasonable way to handle errors.

If instead the first negative argument to the logarithm raised an exception, the application programmer would have to implement complex error handling code in order to get all the "good" values in the array.

Put differently, `NaN` error values maintain the abstraction of arithmetic on arrays, rather than exposing the lower-level implementation detail of looping over elements.
---
### Answer by username_11 on 2023-08-15. Score: 4
IEEE-754 actually makes a number of affordances for different ways of handling erroneous conditions, most of which were sadly ignored or implemented poorly by programming languages; in short, *it should be up to the programmer to decide on an application-specific basis*, and adhering to what the standard actually says will get you there.

IEEE-754 specifies a number of *exceptions*. An exception can be signalled after performing an arithmetic operation; for example, the division-by-zero exception will be signalled if you (shocker) divide a (nonzero) number by zero, and the invalid operation exception will be signalled if you add infinities of opposite sign.

When an exception is signalled, the default behaviour is to set a corresponding *status flag*, compute an alternate result to use instead, and resume execution. For instance, following an invalid operation, you will get a nan, and following division by zero, you will get an infinity.

Already, we can see two different error-handling strategies. We could check if some result is nan. But we could also: clear all the status flags; perform some computation; check the value of the status flags. If you see that the invalid operation status flag got set, then you know that you performed an invalid operation somewhere.

But IEEE-754 also specifies some alternate exception behaviours that an implementation can optionally support. Two are of interest. You could have the operation throw an error (if your language supports error-throwing and unwinding); this is the other error-handling strategy you suggest. You could also specify some special code to be run when the exception is signalled, which would be able to examine the problematic operation and its arguments, and execute arbitrary code to compute an alternate result to be used instead (and continue operation). This could be useful if, for example, [you think that 0/0 should be 0](https://www.jsoftware.com/papers/eem/0div0.htm).

These two alternate exception-handling strategies could be unified into one if you support something like algebraic effect handlers or the common lisp condition system.

It is worth noting that, although x86 supports trapping exceptions, riscv does not, and on arm it is an optional feature implemented only by apple. This makes it difficult to implement them performantly and portably. One approach is as follows: execute a large chunk of straight-line math code with no side effects as-is, then check the status flags. If a status flag got set that is associated with alternate exception-handling behaviour, then re-execute that code with special instrumentation checking for exceptions after each operation.
> **Comments:**
> **username_12** (2023-08-15): IEEE-754 also defines a concept of "signalling" vs "quiet" NaNs -- a "signalling" NaN is basically throwing an exception that aborts the current compilation.  Support for signalling NaNs is optional, though.  
> **username_13** (2023-08-17): one thing to point out is that the lack of language is largely the fault of ieee and CPU designers. the modes are specified by global CPU flags rather than per operation which makes composing different modes in programs very hard to do well  
> **username_11** (2023-08-17): Explicit dataflow would be valuable, but I'm not asking the languages to support anything more than ieee-754 and the cpu architectures support.  
---
### Answer by username_14 on 2023-08-16. Score: 4
This doesn't apply to just division by zero.

First, a quick note on terminology. IEEE-754 distinguishes an *exception* from a *trap*. An exception is an event that may occur, and a trap is one possible response to that condition occurring.

The IEEE-754 standard defines five exceptions:

* Invalid operation: mathematically undefined (e.g. $\sqrt{-1}$).
* Division by zero: an operation on finite operands gives an exact infinite result. The 1985 revision only defined this for actual division by zero, but later revisions include things like $\log 0$.
* Overflow: a finite result is too large to be represented accurately.
* Underflow: a result is so small that it is outside the normal range.
* Inexact: the exact unrounded result is not representable exactly.

The first three are called "common exceptions", and usually can't be ignored when they occur. The last two, despite not being "common", are in fact extremely common: almost all floating point operations "raise" those exceptions and they can usually be ignored. It's actually quite rare that (say) a division operation returns an exact result.

The IEEE-754 standard specifies that whether or not each kind of exception actually causes a trap can be separately controlled. If the exception's trap is enabled, and the exception occurs, then a platform-specific stuff trap occurs (e.g. `SIGFPE` on Unix). If the exception's trap is disabled, then a "reasonable" value is returned and a flag is set recording that the exception occurs.

The exact value returned depends on a bunch of factors:

* Invalid operation returns a quiet `NaN`.
* Division by zero returns positive or negative `Inf`.
* Overflow returns either `Inf`, or the representable number of largest magnitude, depending on the rounding mode.
* Underflow returns a subnormal number or zero (which is technically just a kind of subnormal number), respecting the rounding mode.
* Inexact returns a rounded value.

When you raise a trap, there is then the question as to how this trap is reported. This is an especially important question for automatic vectorisation; suppose you have three parallel division operations that the compiler decides could be performed in a 4-way SIMD unit. Well that's nice, but if division by zero traps are turned on, you had better guarantee that the "unused" SIMD lane contains values that can't trap.

Some architectures, such as Cray-1 and Alpha AXP, made the design decision that, even when programmers want trapping arithmetic exceptions, it's a rare occurrence. Therefore, arithmetic exceptions don't necessarily need to trap in the precise location where they occurred in release code.

The Alpha has a "trap barrier" instruction `TRAPB` which checks the trap flags to see if a trap occurred and raise it if appropriate. For debug-mode compilation, the compiler might insert more `TRAPB` instructions than it would in a release-mode compilation. This decision makes for a much simpler superscalar CPU, and gives much better power performance, despite not being technically IEEE-754 compliant.

Note that this behaviour fits with the way that programming languages typically define trapping arithmetic handlers: a trap is raised by a high-level language concept such as a *statement* or a *block*, rather than a CPU instruction.
> **Comments:**
> **username_0** (2023-08-16): $\sqrt{-1}$ is actually the imaginary unit $i$.  
> **username_14** (2023-08-16): @TheEmptyStringPhotographer First off, in $\mathbb{C}$, there is no *principal* square root of $-1$. But more importantly, $i$ is not representable as a IEEE-754 floating point number. Introducing `+Inf`, `-Inf`, and `NaN` makes the floating point system algebraically closed without introducing complex numbers.  
---
### Answer by username_4 on 2023-08-17. Score: 2
Much of the performance cost associated with exceptions not comes from the need to test for the exceptional condition, but rather with the fact that actions which would otherwise be easily recognizable as having no side effects beyond yielding some kind of result, and thus having no side effects in cases where the result is ignored, must all be treated as having potential side effects.

Although a carefully designed approach using latching overflow flags with loosely defined semantics in some situations (e.g. including separate "has an overflow definitely happened" and "has an overflow definitely not happened" checks, where the former could be moved ahead of operations that might cause overflow but the latter could not) could probably offer better performance than NaNs, NaNs are probably the best approach among those that has been widely adopted for dealing with computations which are found to be erroneous.
---
### Answer by username_5 on 2023-08-16. Score: 2
## NaN as Null

As other answers already mentioned, `NaN` is about performance with floating point numbers. And the thing with fp math, is that when you use it, you use a lot of it, and then fp math performance is paramount.

You can think of NaN as the equivalent of `float?` type, that is, nullable number, with `null` replacing a failed computation. Making every math fp operation accept and return a `float?` may sound like an overkill, but that is what effectively happens with IEEE-754 and NaN, as an arbitrary computation may accept and return NaNs.

You can lessen the aNaNoyances of NaN by making this `float?` aspect a little more explicit. For example, in all math contexts, the signature of arguments and returns are always `float?`, a null float internally represented as a `NaN`, and where you need to show or store a represented valid computation, you will need to declare or cast this usage as no null, no NaN, it is really a number with digits, `float`.

## Configurable division

On `int`s, there is a lot of baggage, and on division in particular, a lot of rounding and *failure* modes. Instead of trying to convey them all in syntax, you may adopt a [configurable](https://langdev.stackexchange.com/a/2059) approach.
---
### Answer by username_6 on 2023-08-16. Score: 1
On a language level, considering NaN as error and throwing an exception is a massive issue if you want to implement a component that simply passes values. There, a NaN can be a well-defined input and working around such issues is very very time consuming.
---
