# IsINF / IsNAN — Test for Infinity or Not a Number

Source: https://rungs.dev/docs/ladder-logic/instructions/is-inf-is-nan

> IsINF and IsNAN test one REAL tag for infinity or for "not a number". Covers what produces each value, both Compare-tab boxes, and the same two tests written inside a CMP expression.

**Is Infinity (`IsINF`).** True when the Source value is positive or negative infinity,
such as the result of 1.0 / 0.0. Both signs pass power — there is no separate test for each.

**Is Not a Number (`IsNAN`).** True when the Source value is not a number, such as the
result of 0.0 / 0.0.

Decimal maths can produce answers that are not measurements at all. A `REAL` tag can end up
holding **infinity**, or **NaN** — short for "not a number". Neither is a reading you can act
on, and neither announces itself.

## Where a bad REAL comes from [#where-a-bad-real-comes-from]

Every one of these is the result of ordinary arithmetic on ordinary tags:

| What the rung works out | What lands in the `REAL`      |
| ----------------------- | ----------------------------- |
| `-1.0 / 0.0`            | `-Infinity`                   |
| `1.0 / 0.0`             | `+Infinity`                   |
| `3.0E38 * 10.0`         | `+Infinity` (too big to hold) |
| `0.0 / 0.0`             | `NaN`                         |
| `LN(0.0)`               | `-Infinity`                   |
| `LN(-1.0)`              | `NaN`                         |

A flow calculation that divides by a speed reading is one bad scan away from the first row:
the moment the line stops, the divisor is zero.

`SQRT` is the exception. `SQRT(-9.0)` gives `3.0`, not a NaN, because square root works on
the size of the number and ignores the minus sign. That means a negative reading gives you a
plausible-looking answer instead of an obvious fault, so check the sign separately if it
matters.

## Why a compare won't catch it [#why-a-compare-wont-catch-it]

The obvious rung — compare the tag and raise an alarm — catches one of these values and is
completely blind to the other:

| With `Ratio` holding | `GT(Ratio, 0.0)` | `LT(Ratio, 0.0)` | `EQ(Ratio, Ratio)` |
| -------------------- | ---------------- | ---------------- | ------------------ |
| `+Infinity`          | true             | false            | true               |
| `-Infinity`          | false            | true             | true               |
| `NaN`                | **false**        | **false**        | **false**          |

**Infinity compares normally.** It is simply bigger than every number (or smaller, if
negative), so a high-limit alarm does catch it — but it tells you the limit was passed, not
that the maths broke. `IsINF` is how you tell a genuinely huge reading apart from a divide
by zero.

**NaN fails every comparison**, including being equal to itself. `GT`, `LT` and `EQ` all
answer "no" forever, so a rung written to catch a bad value never fires and nothing looks
wrong. `IsNAN` is the only test that answers yes. (`NE` is the mirror image: it answers
_true_ for a NaN, because "not equal" is the one comparison a NaN satisfies.)

## Using them in a rung [#using-them-in-a-rung]

Each instruction reads a single `REAL` tag and decides the rung, exactly like a contact.

| Instruction | Passes power when                        |
| ----------- | ---------------------------------------- |
| `IsINF`     | the tag holds `+Infinity` or `-Infinity` |
| `IsNAN`     | the tag holds a NaN                      |

Both live on the **Compare** tab of the ladder toolbar, next to [`EQ` and its
friends](https://rungs.dev/docs/ladder-logic/instructions/compare). Each rung below raises the same `Sts_FlowBad` alarm — one for infinity,
one for NaN:

```ladder
IsINF(FlowRate)OTE(Sts_FlowBad);
```

```ladder
IsNAN(FlowRate)OTE(Sts_FlowBad);
```

A tag can be one or the other, never both: infinity is a direction, NaN is "no answer at
all". To catch either, put the two boxes on parallel branches, or write the single
[`CMP`](https://rungs.dev/docs/ladder-logic/instructions/cmp) on the next page.

## Operands [#operands]

| Name     | Type   | What it is      |
| -------- | ------ | --------------- |
| `source` | `REAL` | The tag to test |

`source` must be a **tag**, or one element of a `REAL` array — `IsINF(Samples[2])` is fine.
A typed-in number is not accepted, and neither is a `DINT` or a `BOOL` tag. That is not a
Studio limitation: a whole number has no way to be infinite, so there would be nothing to
test.

## Like a contact, not like a coil [#like-a-contact-not-like-a-coil]

Both are **input** instructions, so they go to the left of the rung and something else ends
it. A rung that finishes on `IsINF` will not compile, the same way a rung that finishes on
`XIC` will not.

When the rung in front of them is false they are not executed at all, and the rung simply
stays false.

## The same tests inside CMP [#the-same-tests-inside-cmp]

[`CMP`](https://rungs.dev/docs/ladder-logic/instructions/cmp) accepts `IsINF` and `IsNAN` as functions inside its expression, which is how
you ask about two things at once:

```
CMP(IsINF(FlowRate) || IsNAN(FlowRate)) OTE(Sts_FlowBad)
```

That rung is true for infinity **and** for NaN, in one box. The
[expressions page](https://rungs.dev/docs/ladder-logic/expressions) lists everything else an expression accepts. They are the
only two functions `CMP` takes that [`CPT`](https://rungs.dev/docs/ladder-logic/instructions/cpt) does not — `CPT` has to produce a number
to store, and "is this infinite?" is a yes-or-no answer.

They are not available in Structured Text.

## Reading the value on screen [#reading-the-value-on-screen]

A `REAL` tag holding one of these shows as `Infinity`, `-Infinity` or `NaN` in Studio's tag
list, so you can see at a glance which one you have.

Studio 5000 Logix Designer® spells them very differently, and a tag's **Style** setting changes
the spelling again:

| The tag holds          | Style `Float` | Style `Exponential` |
| ---------------------- | ------------- | ------------------- |
| `+Infinity`            | `1.$`         | `1.#INF0000e+000`   |
| `-Infinity`            | `-1.$`        | `-1.#INF0000e+000`  |
| A NaN from `0.0 / 0.0` | `-1.#IND`     | `-1.#IND0000e+000`  |
| A NaN from `LN(-1.0)`  | `1.#QNAN`     | `1.#QNAN000e+000`   |

Both of the last two rows are still a NaN, and `IsNAN` passes power for either — read them as one
condition, not as two different faults. Neither program lets you **type** any of these spellings
into a tag, which is the same point as before: a bad `REAL` only ever arrives from arithmetic.