I wrote an article last November showing how to make your isNaN() calls 12x faster. Today, thanks to a tip from the comments on that article, I’ll show you how to make your isNaN() calls even even faster! (UPDATE: see the definitive article on isNaN for much more!)

The comment I’m referring to goes one step further than my approach last time by recognizing that a Number that is NaN is not even equal to itself and, therefore, the isNaN test can be even further reduced to this:

private function myNewIsNaN(val:Number): Boolean
{
	return val != val;
}

The author, skyboy, claims it’s about twice as fast as my version but admits that he hasn’t tested on Flash Player 10.1. Let’s test this claim with Flash Player 10.1 with an extension to the test app from last time:

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 = 10000000;
			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));
 
			beforeTime = getTimer();
			for (i = 0; i < NUM_ITERATIONS; ++i)
			{
				myNewIsNaN(local33);
			}
			log("myNewIsNaN(33): " + (getTimer()-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < NUM_ITERATIONS; ++i)
			{
				myNewIsNaN(localNaN);
			}
			log("myNewIsNaN(NaN): " + (getTimer()-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < NUM_ITERATIONS; ++i)
			{
				local33 != local33;
			}
			log("new inline for 33: " + (getTimer()-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < NUM_ITERATIONS; ++i)
			{
				localNaN != localNaN;
			}
			log("new inline for NaN: " + (getTimer()-beforeTime));
		}
 
		private function myIsNaN(val:Number): Boolean
		{
			return !(val <= 0) && !(val > 0);
		}
 
		private function myNewIsNaN(val:Number): Boolean
		{
			return val != val;
		}
	}
}

What’s new in the above is the addition of myNewIsNaN and the inline version of it. So, let’s get to the performance results so we can compare the two versions:

Environment val = 33 val = NaN
isNaN myIsNaN (old) inline (old) myIsNaN (new) inline (new) isNaN myIsNaN (old) inline (old) myIsNaN (new) inline (new)
3.0 Ghz Intel Core 2 Duo, Windows XP 251 122 28 91 23 244 122 28 209 23
2.0 Ghz Intel Core 2 Duo, Mac OS X 329 136 43 117 35 321 137 44 111 34

As you can see, the new approach supplied by skyboy is indeed faster than the original approach. However, it does not appear to be twice as fast but rather more like 20% faster in inline form. Still, the speedup is real and much appreciated so it should be used in place of the original approach. As an added benefit, it is more compact and perhaps more straightforward to comprehend. I would still recommend a comment:

val != val; // inline isNaN()

Finally, the bug I filed with Adobe regarding this inefficiency has been marked as “resolved”, so we should see some speedup without this inlining in a future version of Flash Player.