NaN in Practice: What It Is, When to Use It, and How to Parse It Safely
What is NaN?
NaN means “Not a Number.” It is the standard floating-point result for invalid math, defined by the IEEE 754 standard.
Examples:
0 / 0
sqrt(-1)
log(-10)
inf - inf
The important rule: NaN is not equal to anything, including itself.
x = float('nan')
print(x == x) # False
That is why NaN is useful as a signal, but dangerous if you forget to check it.
IEEE 754 Standard
Most modern languages and CPUs follow IEEE 754 for floating-point numbers.
Two common NaN variants exist:
- Quiet NaN: produced in normal invalid math; often used as a safe sentinel
- Signaling NaN: can raise a floating-point exception when used
In practical engineering work, quiet NaN is the important one. It is the most common “invalid value” representation in C, C++, Python, JavaScript, Rust, and many embedded targets.
When do we use NaN?
Use NaN when a float is mathematically invalid but still needs to be represented as a numeric value.
Typical cases:
- missing sensor input
- calibration not ready yet
- invalid measurement before filtering
- sentinel for “no valid value” in arrays or buffers
- debugging uninitialized float data in embedded code
Example:
float temp = NAN; // “value is not valid yet”
This is useful when you want to detect a bad reading without crashing the program.
How to create and parse NaN in different languages
| Language | Create NaN | Check NaN | Parse from string |
|---|---|---|---|
| Python | float('nan') or math.nan | math.isnan(x) | float('nan') |
| JavaScript | Number.NaN or parseFloat('abc') | Number.isNaN(x) | parseFloat('NaN') |
| C/C++ | NAN from <math.h> or std::nan() | isnan(x) | strtof() then validate |
| Java | Double.NaN | Double.isNaN(x) | Double.parseDouble("NaN") |
| Go | math.NaN() | math.IsNaN(x) | strconv.ParseFloat("NaN", 64) |
| Rust | f32::NAN / f64::NAN | x.is_nan() | "NaN".parse::<f64>() |
Python
import math
x = float('nan')
print(math.isnan(x)) # True
JavaScript
const x = Number.NaN;
console.log(Number.isNaN(x)); // true
console.log(x === x); // false
C/C++
#include <math.h>
#include <stdio.h>
float x = NAN;
if (isnan(x)) {
printf("invalid value\n");
}
Go
package main
import (
"fmt"
"math"
)
func main() {
x := math.NaN()
fmt.Println(math.IsNaN(x))
}
Pros of NaN
- clearly represents invalid floating-point data
- helps detect bad math early
- useful in numeric pipelines and signal processing
- common standard across hardware and languages
Cons of NaN
- comparisons are tricky:
NaN != NaN - it can silently propagate through calculations
- not always safe in JSON, logs, or databases
- many developers forget to check it, leading to hidden bugs
- in business logic, a missing value is often better as
null,None, or an explicit status field
Practical protection rules
Always check before using a float
isnan(x)before arithmetic or comparisons
Use NaN only for numeric invalid states, not as a normal business value
- if the value is missing, prefer
null/None/ optional types
- if the value is missing, prefer
Convert at system boundaries
- JSON:
NaNis not valid in standard JSON - APIs: send
nullor a structured error instead
- JSON:
Log and fail fast
- if invalid data enters the system, record it instead of letting it spread silently
Prefer validation before parsing
parseFloat('abc')may return NaN; check the result immediately
Good engineering practice
For most application code, this rule is best:
- use
NaNinside numeric algorithms when needed - convert to
null/Nonebefore API, database, or JSON output - validate every parsed float before using it in control logic
Bottom line
NaN is a standard IEEE 754 mechanism for “invalid floating-point value.” It is useful in scientific, signal-processing, and embedded code, but it must be handled explicitly.
If you do not check it, NaN becomes a silent data bug.
Use it when the data is invalid but still belongs to a numeric pipeline. Use null, None, or an explicit error flag when the value is absent from the business domain.
Practical takeaway: NaN is powerful, but only safe when you validate it early and convert it to a cleaner representation at boundaries.