7

I still do not understand what a NaN or a (Number which isn´t a real Number) exactly is.

Main question:

  1. What is a NaN value or NaN exactly (in the words of a non-math professor)?

Furthermore i have a few questions about the whole circumstance, which giving me complaints in understanding what a NaN should be, which are not necessary to answer my main question but desired:

  1. What are operations which causing a NaN value as result?

  2. Why is the result of 0.0 / 0.0 declared as undefined? Shouldn´t it be 0?

  3. Why can´t the result of any mathematical operation be expressed by a floating point or integer number? How can it be that a value is unrepresentable?

  4. Why is the square root of a negative number not a real number?

  5. Why is NaN not equivalent to indefinite?

I did not found any understandable explanation of what NaN is for me in the whole Internet, including here on Stack Overflow.


Anyway I want to provide my research as links to places, i have scanned already to find an understandable answer to my question, even if some links go to the same question in other programming languages, but did not gave me the desired clear informations in total:

Wikipedia:

https://en.wikipedia.org/wiki/NaN

https://en.wikipedia.org/wiki/IEEE_754

Other:

http://foldoc.org/Not-a-Number

https://www.youtube.com/watch?v=HN_UmxIVS6M

https://www.youtube.com/watch?v=9EsHjXftO7s

Stack Overflow:

Similar or same questions for other Languages (I provide them as far as i think the base of the understanding is very similar if not the same):

In Java, what does NaN mean?

What is the rationale for all comparisons returning false for IEEE754 NaN values?

(Built-in) way in JavaScript to check if a string is a valid number

JavaScript: what is NaN, Object or primitive?

Not a Number (NaN)

Questions for C++:

What is difference between quiet NaN and signaling NaN?

Checking if a double (or float) is NaN in C++

Why does NaN - NaN == 0.0 with the Intel C++ Compiler?

What is the difference between IND and NAN numbers


Thank you for all helpful answers and comments.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 2
    `Why is the result of 0.0 / 0.0 declared as undefined? Shouldn´t it be 0?` Why should it be 0? What is anything divided by 0? Not 0. – tkausl Dec 14 '19 at 12:20
  • 4
    Please ask only one question – Thomas Sablik Dec 14 '19 at 12:21
  • 5
    Also, most of your question should be asked on a math QA site, not a programming one. – tkausl Dec 14 '19 at 12:22
  • @tkausl `lim x->0 x*x / x = 0` – Thomas Sablik Dec 14 '19 at 12:23
  • @ThomasSablik Why did you choose `x*x` as numerator? You can generate any result using such a limit with an appropriate numerator. – walnut Dec 14 '19 at 12:26
  • some questions are purely about maths. Eg 5. or 7. btw real numbers is a maths concept that is very different from floating point numbers. Actually real numbers have some really weird properties, eg there are as many real numbers between 0 and 1 as there are between 1 and infinity, you wont get such features from floating point numbers, in some sense real numbers are rather unreal – 463035818_is_not_an_ai Dec 14 '19 at 12:27
  • @walnut because tkausl said it's not 0 and I showed one example where it is 0. Of course I know 0/0 is undefined because it can yield any value. – Thomas Sablik Dec 14 '19 at 12:28
  • @ThomasSablik Sorry i´ve a made a confusion.The header question is the main one. I just wanted to provide as much informations as possible. – RobertS supports Monica Cellio Dec 14 '19 at 12:38
  • _"but did not gave me the desired clear informations in total"_ It's hard not to just repeat that stuff if we don't know what you didn't understand about it. – Lightness Races in Orbit Dec 14 '19 at 12:43
  • @LightnessRaceswithMonica The, now edited, subquestions, represent what i do not understand. That was the reason i posted them. – RobertS supports Monica Cellio Dec 14 '19 at 12:44
  • @LightnessRaceswithMonica What is NaN exactly? This is my question. Nothing more, nothing less. – RobertS supports Monica Cellio Dec 14 '19 at 12:49
  • Then that is already answered on the Wikipedia page, in quite some detail. There is no other information we can provide. – Lightness Races in Orbit Dec 14 '19 at 12:49
  • @LightnessRaceswithMonica The Wikipedia page does not resolve my concerns. I am trying that someone might be able to bring the understanding of what NaN is closer to me, as i am acting really hard in understanding it. That´s why i made the question. – RobertS supports Monica Cellio Dec 14 '19 at 13:04
  • It does resolve your concerns. Study it again. If you still struggle, ask _specifically_ about the _specific_ thing you do not understand. You cannot just not understand all of it. – Lightness Races in Orbit Dec 14 '19 at 13:17
  • @RobertS: "*I am trying that someone might be able to bring the understanding of what NaN is closer to me*" It's kind of hard to explain it in a way that you can understand when you can't explain what it is that you *don't* understand. You say "what is NaN exactly," we point you to a page that "exactly" tells you that, but then you say you don't understand and then you repeat your question. You need to narrow it down to what you don't understand about it. – Nicol Bolas Dec 14 '19 at 23:00
  • @ThomasSablik `lim x->0 x*x / x = 0` is **limit** equation. Using `0` w/o limit, one gets back to original question, i.e. `0/0 * 0 = ?`. Let solve it algebraically: `x/x * x = 1 * x = x = 0`. But `x/x = 1`. So `0/0 = 1` and `0² / 0¹ = 0¹ = 0`. Better to go directly with powers substractions. `0*0*0/0 = NaN` but `0³/0¹ = 0²`. – Yarl Jul 27 '23 at 08:38
  • @Yarl `x/x * x = 1 * x` is wrong and everything follwing it is also wrong. It's only correct for `x != 0`. – Thomas Sablik Jul 27 '23 at 10:18
  • @ThomasSablik, what about `0⁰ = (a-a)ⁿ⁻ⁿ = (a-a)ⁿ/(a-a)ⁿ = 1 ⇒ 0¹/0¹ = 0⁰ = 1`. No matter true interpretation, result of limit equation is not result of division. Results tend to limit result indefinitely but never reaches it. – Yarl Jul 27 '23 at 17:53
  • @RobertSsupportsMonicaCellio What is dividing? `8/2=4` — result shows number of occurences of divisor. `2+2+2+2 = 2*4 = 8`. So `0/3=0` and `3*0=0`. What about `3/0`? Is it `0`? if, then `0*0=3`. Obviously there is no such result. On other hand `0*0=0` so `0/0=0`? Maybe. How many occurences of `0` are in `0`? Just `1`. In terms of powers `0¹/0¹=0⁰=1`. That would render `1=0`. Also `3*0=0` so `0/0=3` or `0/0=1/3`? It is property of `0` divisor not dividend that drives `NaN` for `x/0` for any float number including `0.0`. Everyday arithmetic does not know `0` division. – Yarl Jul 27 '23 at 19:19
  • @Yarl You can't start with wrong math to prove anything. `0¹/0¹ = 0⁰` is wrong. `(a-a)ⁿ/(a-a)ⁿ = 1` is wrong. To be honest, I don't even understand, what you're actually trying to prove or how this is related to the question or my comment. – Thomas Sablik Jul 28 '23 at 14:45
  • @ThomasSablik, `0*0=0`, so `0/0=0`, `0/0=1`, or `0/0=NaN`. Does not matter. It is interesting that you clearly says that `x²/x for x lim → 0 = 0` but you are telling that `x¹/x¹ * x for x lim → 0 = 0` does not exists, right? _I showed one example where it is 0_. How is possible to have that one example? Either you show no 0-division example since `x > 0 ∧ x ⋘ 1` upon closing on limit or you showed it and `x=0`. If you showed it, then either you got `0*0=0` or `1*0=0` since `NaN*0=NaN`. – Yarl Jul 28 '23 at 15:38

4 Answers4

7

You've asked a series of great questions here. Here's my attempt to address each of them.

What is a NaN value or NaN exactly (in the words of a non-math professor)?

Let's suppose you're working with real numbers - numbers like 1, π, e, -137, 6.626, etc. In the land of real numbers, there are some operations that usually can be performed, but sometimes don't have a defined result. For example, let's look at logarithms. You can take the logarithm of lots of real numbers: ln e = 1, for example, and ln 10 is about 2.3. However, mathematically, the log of a negative number isn't defined. That is, we can't take ln (-4) and get back a real number.

So now, let's jump to programming land. Imagine that you're writing a program that or computes the logarithm of a number, and somehow the user wants you to divide by take the logarithm of a negative number. What should happen?

There's lots of reasonable answers to this question. You could have the operation throw an exception, which is done in some languages like Python.

However, at the level of the hardware the decision that was made (by the folks who designed the IEEE-754 standard) was to give the programmer a second option. Rather than have the program crash, you can instead have the operation produce a value that means "you wanted me to do something impossible, so I'm reporting an error." The way this is done is by having the operation produce the special value NaN ("Not a Number"), indicating that, somewhere in your calculation, you tried to perform an operation that's mathematically not defined.

There are some advantages to this approach. In many scientific computing settings, the code performs a series of long calculations, periodically generating intermediate results that might be of interest. By having operations that aren't defined produce NaN as a result, the programmer can write code that just does the math as they want it to be done, then introduce specific spots in the code where they'll test whether the operation succeeded or not. From there, they can decide what to do. Contrast this with tripping an exception or crashing the program outright - that would mean the programmer either needs to guard every series of floating point operations that could fail or has to manually test things herself. It’s a judgment call about which option is better, which is why you can enable or disable the floating point NaN behavior.

What are operations which causing a NaN value as result?

There are many ways to get a NaN result from an operation. Here's a sampler, though this isn't an exhaustive list:

  1. Taking the log of a negative number.
  2. Taking the square root of a negative number.
  3. Subtracting infinity from infinity.
  4. Performing any arithmetic operation on NaN.

There are, however, some operations that don't produce NaN even though they're mathematically undefined. For example, dividing a positive number by zero gives positive infinity as a result, even though this isn't mathematically defined. The reason for this is that if you take the limit of x / y for positive x as y approaches zero from the positive direction, the value grows without bound.

Why is the result of 0.0 / 0.0 declared as undefined? Shouldn´t it be 0?

This is more of a math question than anything else. This has to do with how limits work. Let's think about how to define 0 / 0. One option would be to say the following: if we look at the expression 0 / x and take the limit as x approaches zero, then we'd see 0 at each point, so the limit should be zero. On the other hand, if we look at the expression x / x and take the limit as x approaches 0, we'd see 1 at each point, so the limit should be one. This is problematic, since we'd like the value of 0 / 0 to be consistent with what you'd find as you evaluated either of these expressions, but we can't pick a fixed value that makes sense. As a result, the value of 0 / 0 gets evaluated as NaN, indicating that there's no clear value to assign here.

Why can´t the result of any mathematical operation be expressed by a floating point or integer number? How can it be that a value is unrepresentable?

This has to do with the internals of IEEE-754 floating point numbers. Intuitively, this boils down to the simple fact that

  1. there are infinitely many real numbers, infinitely many of which have infinitely long non-repeating decimals, but
  2. your computer has finite memory.

As a result, storing an arbitrary real number might entail storing an infinitely long sequence of digits, which we can't do with our finite-memory computers. We therefore have floating point numbers store approximations of real numbers that aren't staggeringly huge, and the inability to represent values results from the fact that we're just storing approximations.

For more on how the numbers are actually stored, and what this means in practice, check out the legendary guide "What Every Programmer Should Know About Floating-Point Arithmetic"

Why is the square root of a negative number not a real number?

Let's take √(-1), for example. Imagine this is a real number x; that is, imagine that x = √(-1). The idea of a square root is that it's a number that, if multiplied by itself, gives you back the number you took the square root of.

So... what number is x? We know that x ≠ 0, because 02 = 0 isn't -1. We also know that x can't be positive, because any positive number times itself is a positive number. And we also know that x can't be negative, because any negative number times itself is positive.

We now have a problem. Whatever this x thing is, it would need to be not positive, not zero, and not negative. That means that it's not a real number.

You can generalize the real numbers to the complex numbers by introducing a number i where i2 = -1. Note that no real numbers do this, for the reason given above.

Why is NaN not equivalent to indefinite?

There's a difference between "indefinite" and "whatever it is, it's not a real number." For example, 0 / 0 may be said to be indeterminate, because depending on how you approach 0 / 0 you might get back 0, or 1, or perhaps something else. On the other hand, √(-1) is perfectly well-defined as a complex number (assuming we have √(-1) give back i rather than -i), so the issue isn't "this is indeterminate" as much as "it's got a value, but that value isn't a real number."

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • The folks who designed IEEE 754 did not decide to have operations return a NaN. They decided to give programmers choices. Floating-point exceptions can be trapped or can produce default results. This is intended to be a programmer choice, but incomplete implementations of IEEE 754 may fail to provide that choice. The implementors of such implementations are responsible for the decision to produce a NaN rather than to trap, not the IEEE-754 committee. – Eric Postpischil Dec 14 '19 at 23:37
  • @EricPostpischil Thanks for the correction! Answer updated. – templatetypedef Dec 15 '19 at 00:08
  • @templatetypedef Thank you very much, this is what i have wanted as answers. I´ll need a while to go through all things in detail. Thank you very much. – RobertS supports Monica Cellio Dec 15 '19 at 15:33
  • @templatetypedef, are there any resource for reason of _Taking the log of a negative number_? Let say that `log₃-27 = -3`. – Yarl Jul 27 '23 at 08:42
  • @Yarl The way logs work, we should have that if log_a b = c, then a^c = b. So, for example, log_2 8 = 3 because 2^3 = 8. So if I try computing log_3 (-27), I should get a number x where 3^x = -27. But there’s no real number x that does this, since 3^x is nonnegative for all real x. – templatetypedef Jul 27 '23 at 15:29
  • @templatetypedef, I was skimming trought text, looking forward on technical problem and forgotten "which one is upside". Next time I shall be more patient. I.e. `-3³ = -27` but `3⁻³ = 0.0370…` and as you pointed out `3ˣ > 0` for all real numbers. – Yarl Jul 27 '23 at 17:50
  • Nevertheless, `log₋₃-27` woudl work, it there was some. – Yarl Aug 06 '23 at 21:40
2

For a summary you can have a look at the wikiedia page:

In computing, NaN, standing for not a number, is a member of a numeric data type that can be interpreted as a value that is undefined or unrepresentable, especially in floating-point arithmetic. Systematic use of NaNs was introduced by the IEEE 754 floating-point standard in 1985, along with the representation of other non-finite quantities such as infinities.

On a practical side I would point out this:

If x or y are NaN floating points: then expressions like:

x<y
x<=y
x>y
x>=y
x==x

are always false. However,

x!=x

will be true and this is a way to check if x is NaN or not (see std::isnan).

Another remark is that when some NaN arise in numerical computations you may observe a big slowdown (this can also be a hint when debugging)

NaN operations on Intel CPUs are likely to generate exceptions which invoke microcode, so the relative slowdown probably varies greatly with CPU model.

See NaN slowdown for instance

Picaud Vincent
  • 10,518
  • 5
  • 31
  • 70
1

A floating point number is encoded to a pattern of bits, but not all available bit patterns (for a given number of bits) are used, so there are bit patterns that dont't encode any floating point number. If such patterns are found, they are treated/displayed as NaNs.

mcleod_ideafix
  • 11,128
  • 2
  • 24
  • 32
  • 4
    NaNs do not exist merely because the designers of IEEE-754 neglected to use all available bit patterns. Their existence is intentional, designed, and purposeful. And the patterns are not just “found”; they are deliberately set by initialization or are the specified results of operations. – Eric Postpischil Dec 14 '19 at 13:40
1

Mathematical number systems contain a "set" of values. For example, the positive integers are 0, 1, 2, 3, 4 etc. The negative integers are -1, -2, -3, -4 etc (perhaps -0 too, depending on your branch of mathematics).

In computerland, floating-point numbers additionally have concepts of "infinity" and "not a number", amongst other things. This is like "NULL" for numbers. It means "the floating-point value does not represent a number in the mathematical sense".

They're useful for programmers when they have a float that they don't want to give a number value [yet], and they're also used by the floating-point standards to represent "invalid" results of operations.

You can, for example, get a NaN by dividing zero by zero, an operation with no meaningful value in any branch of mathematics that I'm aware of: how do you share a number of cakes between no people?.

(If you try to do this with integers, which have no concept of NaN or infinity, you instead get a [terribly-named] "floating point exception"; in other words, your program will crash.)

Read more on Wikipedia's article about NaN, which answers pretty much all of your questions.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055