Why check for !isNaN() after isFinite()?
Asked Answered
T

6

32

I came across the goog.math.isFiniteNumber function in the Google Closure Library. What it does is checking whether a given number is both finite and not NaN.

The underlying code is:

goog.math.isFiniteNumber = function(num) {
  return isFinite(num) && !isNaN(num);
};

So, first it checks whether the number is finite using the native isFinite function, and then does an additional check to make sure the number isn't NaN using isNaN.

However, isFinite already returns false in case the argument is NaN. So, what advantages does the check for isNaN provide?

Terminable answered 16/4, 2011 at 22:29 Comment(2)
I think you should ask the author of the code. My best guess is that some buggy (old?) browser treats NaN as finite and the double check is for compatibility only.Arly
It could be some obscure browser (or other javascript implementation) that gets it wrong, the programmer assuming isFinite only tested for +/- infinity, or the programmer just specifying an extra check as a precaution.Belovo
S
-5

If isFinite worked the way isFiniteNumber did, then there would be no reason to write isFiniteNumber. There's probably some browser out there somewhere that treats NaN as finite.

Shareeshareholder answered 16/4, 2011 at 23:2 Comment(5)
I'm wondering which one it might be. Chrome/IE9/Firefox/Opera all behave correctly. Perhaps IE6, but I guess the isFinite function is sufficient in all cases.Terminable
Microsoft claims IE6 supports it: msdn.microsoft.com/en-us/library/h5s8dazc(v=vs.94).aspxShareeshareholder
I'm sorry to say, but this answer is not correct. This is based on just conjecture.Faretheewell
This answer may be conjecture, but it does address the actual question, which is about the fact that, by definition, isNaN is implicit in isFinite. The isNaN call should be pointless -- unless there's a browser out there with an implementation error. But I suspect this is a Closure mistake. I can't find any examples of broken isFinite implementations with Google, and it's notable that elsewhere in the same file, they feel comfortable with the assumption that any value passing isFinite must be a number: goog.math.isInt = function(num) { return isFinite(num) && num % 1 == 0; };Freeholder
(An aside though -- while all implementations I've checked seem to use isNaN inside isFinite, as expected, isNaN itself is weird as hell -- for example ' ' evaluates to the number zero. That's why underscore uses _.isFinite = function(obj) { return isFinite(obj) && !isNaN(parseFloat(obj)); };)Freeholder
F
24

The only difference is this:

!isNan(1/0) // --> true
isFinite(1/0) // --> false

isNaN checks whether the argument is a number or not. The Infinities (+/-) are also numerical, thus they pass the isNaN check, but don't pass the isFinite check.

** Note that any string which can be parsed as a number ("2", "3.14") will cause isNaN to return false.

Hope this helps.

PS: The answer given by user1170379 was very nearly perfect.

Faretheewell answered 30/5, 2013 at 15:47 Comment(4)
So, to answer OP's question, yes, the isNaN check is redundant.Idiographic
@Idiographic is absolutely is not redundant. If it was, it wouldn't have been there. Say you want to check for Infinity. which is a valid number (there can be cases where you're incorporating Infinities into your logic, say in a Maths application). There, !isNaN() would return true but isFinite would be false.Faretheewell
Yep, everything you've said is correct. !isNaN(Infinity) === true, and isFinite(Infinity) === false. So, isFinite(num) && !isNaN(num) === false. That's why the isNaN check is redundant - isFinite captures both the NaN and Infinity failure cases.Idiographic
Holy smoke, I always assumed 1/0 would evaluate to NaN, but I checked it just now and it returns Infinity. 0/0, on the other hand, comes out to NaN. Even more surprising, Wolfram Alpha agrees! Can anyone help me understand this?Avestan
I
3

you might reason out [Why?] after reading this:

NaN doesn't check if the passed value is infinite or not - it checks if the input val evaluates into a "Type: Number" end-result. Because isNaN(string) is accepted, so the: isNaN("3.14") //false (which means true, the given token is duck converted into a type Number successfully )

You may understand that the input value may happen to be an unresolved brute number, even a math operation as simple as: (x/y); which in turn might yield a (+/-infinity) number.

Here x=1, y=0; meaning (1/0).Then isNaN(x/y) will first evaluate to isNaN(1/0); then to isNaN(infinity) //false. Since (1/0)=infinity is of type: "number" ie typeof(1/0) //"number" isNaN should and will return false.

You don't want to put "infinity" where an end result number is expected.

Insistency answered 26/1, 2012 at 0:11 Comment(3)
What does typeof have to do with isNaN? isNaN merely returns true when passed a value that coerces to the numeric value corresponding to IEEE-754 NaN. isNaN is equivalent to function isNaN(x) { x = +x; return x !== x; }.Stoll
sorry Samuel but you didn't grasp the half of it and your function for isNaN should be: function isNaN(x){return x!=x} and not a byte more.Insistency
Samuel's answer is an excellent explanation of how the isNaN function is actually implemented; user1170379's suggestion is how most of us wish it were implemented. For further proof, x={}, isNaN(x)=>true but x!=x=>falseChelate
H
1

Probably for the same reason that I have implemented (isfinite(num) && isfinite(-num)) - I was getting errors from mysql complaining about putting "-nan" into the database even though I had a check for isfinite(field)...

A useful article on this subject is http://jacksondunstan.com/articles/983 which provides an optimization ((d*0.0)==0.0)

Histrionism answered 20/9, 2011 at 23:25 Comment(0)
T
1

isNaN() returns true if the argument is not a number or if the argument is a non-numeric value such as a string or an object.Otherwise, It returns false. Example: isNaN(0/0) =>true; isNaN(2-1) =>false; isFinite() returns true if the argument is a number other than NaN,Infinity or -Infinity.Otherwise, It returns false. Example: isFinite("2000") =>false; isFinite(200/2) =>true;`

Tosspot answered 6/8, 2014 at 7:7 Comment(1)
isFinite("2000") returns true.Gans
P
0

const infiniteNumber = 1/0;
const x = () => {
  return isFinite(infiniteNumber) && !isNaN(infiniteNumber);
};

const y = () => {
  return isFinite(infiniteNumber);
};

const z = () => {
  return !isNaN(infiniteNumber);
};

const t = () => {
  return !isNaN(null);
};

const c = () => {
  return isFinite(null);
};

const u = () => {
  return !isNaN(undefined);
};

const v = () => {
  return isFinite(undefined);
};

console.log(x(),y(),z(),t(),c(),u(),v())

This might be helpful

Payoff answered 7/6, 2024 at 21:28 Comment(0)
S
-5

If isFinite worked the way isFiniteNumber did, then there would be no reason to write isFiniteNumber. There's probably some browser out there somewhere that treats NaN as finite.

Shareeshareholder answered 16/4, 2011 at 23:2 Comment(5)
I'm wondering which one it might be. Chrome/IE9/Firefox/Opera all behave correctly. Perhaps IE6, but I guess the isFinite function is sufficient in all cases.Terminable
Microsoft claims IE6 supports it: msdn.microsoft.com/en-us/library/h5s8dazc(v=vs.94).aspxShareeshareholder
I'm sorry to say, but this answer is not correct. This is based on just conjecture.Faretheewell
This answer may be conjecture, but it does address the actual question, which is about the fact that, by definition, isNaN is implicit in isFinite. The isNaN call should be pointless -- unless there's a browser out there with an implementation error. But I suspect this is a Closure mistake. I can't find any examples of broken isFinite implementations with Google, and it's notable that elsewhere in the same file, they feel comfortable with the assumption that any value passing isFinite must be a number: goog.math.isInt = function(num) { return isFinite(num) && num % 1 == 0; };Freeholder
(An aside though -- while all implementations I've checked seem to use isNaN inside isFinite, as expected, isNaN itself is weird as hell -- for example ' ' evaluates to the number zero. That's why underscore uses _.isFinite = function(obj) { return isFinite(obj) && !isNaN(parseFloat(obj)); };)Freeholder

© 2022 - 2025 — McMap. All rights reserved.