Mathematics7 min readExamples run on PHP 8.5.10

is_nan()

Learn how PHP's is_nan() detects the special Not A Number float, why comparing with NAN never works, and how to guard calculations.

Signature

is_nan(float $num): bool
Available since PHP 4.2.07.48.08.18.28.38.48.5All versions →

Purpose

is_nan() tells you whether a float holds the special value NAN, short for Not A Number. NAN is produced by mathematical operations that have no defined result, such as taking the square root of a negative number, computing INF / INF, or doing arithmetic with a value that is already NAN.

Despite the name, NAN is a real value of type float. It can sit in variables, arrays and function results like any other float, which is why a dedicated check is needed to catch it before it spreads through later calculations.

Signature

Parameters and defaults

  • $num: the float to inspect. There are no other parameters and no default values.

Because the parameter is typed float, an integer argument is converted to a float automatically, and an integer can never be NAN, so the result is false. In the default coercive typing mode, a numeric string such as "2.5" is converted too. A non-numeric string such as "abc" throws a TypeError.

Return value and failure cases

The function returns true when the value is NAN and false for every other float, including INF, -INF, 0.0 and ordinary numbers. It does not emit warnings for a valid float. The only failure case is passing a value that cannot be coerced to float, which raises a TypeError.

Example 1: detecting an undefined result

The square root is undefined for negative real numbers, so sqrt(-1) yields NAN.

Example
<?php
$nan = sqrt(-1);

var_dump($nan, is_nan($nan));
Output
float(NAN)
bool(true)

var_dump() prints the float as float(NAN), and is_nan() confirms it with bool(true).

Example 2: why comparison operators fail

NAN is not equal to anything, including itself. This follows the IEEE 754 floating-point standard, and PHP behaves the same way.

Example
<?php
$value = NAN;
echo json_encode([
    'equal' => $value === NAN,
    'loose' => $value == NAN,
    'is_nan' => is_nan($value),
]);
echo "\n";
Output
{"equal":false,"loose":false,"is_nan":true}

Both comparisons return false, even though $value really is NAN. Only is_nan() answers the question correctly.

Example 3: telling NAN apart from infinity

Some results look similarly strange but are not NAN. The fdiv() function follows IEEE rules, so dividing zero by zero gives NAN while dividing one by zero gives INF.

Example
<?php
$values = [
    'sqrt_negative' => sqrt(-4),
    'zero_over_zero' => fdiv(0, 0),
    'one_over_zero' => fdiv(1, 0),
    'ordinary' => 2.5,
];
$report = [];
foreach ($values as $label => $value) {
    $report[$label] = is_nan($value);
}
echo json_encode($report), "\n";
Output
{"sqrt_negative":true,"zero_over_zero":true,"one_over_zero":false,"ordinary":false}

Infinity is a different category of value. is_nan(INF) is false, and you would use is_infinite() to detect it.

Edge cases

  • Propagation: any arithmetic that involves NAN produces NAN. A single bad value early in a chain of calculations can contaminate the final total, so check at boundaries where input enters or where a risky function is called.
  • Infinity is not NAN: INF and -INF return false. Use is_finite() if you want to reject NAN and both infinities in one check, because it returns false for all three.
  • Integer division: the / operator with a zero divisor throws DivisionByZeroError in PHP 8, and so does intdiv(). Neither produces NAN. Use fdiv() when you want IEEE results.
  • Searching arrays: in_array(NAN, $list) and array_search() will not find a NAN value, because the comparison never succeeds. Filter with array_filter($list, 'is_nan') instead.
  • JSON: json_encode() cannot represent NAN or infinity. By default it returns false, so replace or reject these values before encoding results.

Common mistakes

  1. Writing $x === NAN or $x == NAN. These are always false. Call is_nan($x).
  2. Writing $x !== $x as a trick without a comment. It does work for NAN, but it is obscure. Prefer the named function for readability.
  3. Assuming is_nan() validates user input. A string like "NAN" is not numeric, so it throws a TypeError instead of returning true. Validate and convert input first, for example with is_numeric(), then check the resulting float.
  4. Treating INF as NAN. Overflow and division by zero in float arithmetic give infinity, not NAN. Check both conditions separately, or use is_finite().
  5. Ignoring the result of risky math. Functions such as sqrt(), log() and acos() return NAN when given values outside their domain. Test their results before storing or displaying them.
  • is_finite(): checks that a float is neither infinite nor NAN.
  • is_infinite(): checks whether a float is INF or -INF.
  • fdiv(): performs IEEE 754 division without throwing on a zero divisor.
  • is_numeric(): checks whether a value is a number or numeric string before conversion.

Recap

is_nan() takes one float and returns a boolean. It is the only reliable way to detect NAN, because NAN never equals anything, not even itself. Remember that INF is not NAN, that integers are never NAN, and that non-numeric strings cause a TypeError. Use it to guard results from math functions before they spread through your calculations.

Tested examples

Detecting NAN from sqrt(-1)
<?php
$nan = sqrt(-1);

var_dump($nan, is_nan($nan));
Output
float(NAN)
bool(true)
Comparison operators never match NAN
<?php
$value = NAN;
echo json_encode([
    'equal' => $value === NAN,
    'loose' => $value == NAN,
    'is_nan' => is_nan($value),
]);
echo "\n";
Output
{"equal":false,"loose":false,"is_nan":true}
NAN versus infinity and ordinary floats
<?php
$values = [
    'sqrt_negative' => sqrt(-4),
    'zero_over_zero' => fdiv(0, 0),
    'one_over_zero' => fdiv(1, 0),
    'ordinary' => 2.5,
];
$report = [];
foreach ($values as $label => $value) {
    $report[$label] = is_nan($value);
}
echo json_encode($report), "\n";
Output
{"sqrt_negative":true,"zero_over_zero":true,"one_over_zero":false,"ordinary":false}