You cannot directly check if a value is NaN by comparing with it. AS3, AS2, and JavaScript therefore provide a useful isNaN() function to do this very check. However, it is very slow. Today I’ll show you a workaround that results in a faster isNaN(): (UPDATE: see the definitive article on isNaN for much more!)

Consider this bit of code

!(val <= 0) && !(val > 0)

This is apparently a contradiction since a number cannot be both less than and greater than 0. If you read my article on Details of NaN, you may remember that any comparison with NaN is false. Therefore, if val is false, we will have:

!false && !false

Which is then:

true && true

Which is clearly true. We have therefore devised our own isNaN(). We can encapsulate it cleanly in a function:

function myIsNaN(val:Number): Boolean
{
	return !(val <= 0) && !(val > 0);
}

And we can also test its speed:

package
{
	import flash.display.*;
	import flash.utils.*;
	import flash.text.*;
 
	/**
	*   An app to test improved versions of isNaN()
	*   @author Jackson Dunstan
	*/
	public class FastIsNaNTest extends Sprite
	{
		public function FastIsNaNTest()
		{
			var logger:TextField = new TextField();
			logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(logger);
			function log(msg:*): void { logger.appendText(msg + "\n"); }
 
			const NUM_ITERATIONS:int = 1000000;
			var i:int;
			var beforeTime:int;
			var local33:Number = 33;
			var localNaN:Number = NaN;
 
			beforeTime = getTimer();
			for (i = 0; i < NUM_ITERATIONS; ++i)
			{
				isNaN(local33);
			}
			log("isNaN(33): " + (getTimer()-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < NUM_ITERATIONS; ++i)
			{
				isNaN(localNaN);
			}
			log("isNaN(NaN): " + (getTimer()-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < NUM_ITERATIONS; ++i)
			{
				myIsNaN(local33);
			}
			log("myIsNaN(33): " + (getTimer()-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < NUM_ITERATIONS; ++i)
			{
				myIsNaN(localNaN);
			}
			log("myIsNaN(NaN): " + (getTimer()-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < NUM_ITERATIONS; ++i)
			{
				!(local33 <= 0) && !(local33 > 0)
			}
			log("inline for 33: " + (getTimer()-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < NUM_ITERATIONS; ++i)
			{
				!(localNaN <= 0) && !(localNaN > 0)
			}
			log("inline for NaN: " + (getTimer()-beforeTime));
		}
 
		private function myIsNaN(val:Number): Boolean
		{
			return !(val <= 0) && !(val > 0);
		}
	}
}

Here are the results:

Environment isNaN(33) isNaN(NaN) myIsNaN(33) myIsNaN(NaN) inline for 33 inline for NaN
2.2 Ghz Intel Core 2 Duo, 2 GB RAM, Mac OS X 10.6 61 60 12 12 5 5

This shows myIsNaN() is five times as fast as isNaN() and an inlined version is twice as fast as that. For math-heavy code in performance-critical areas, this could be a major speed boost!