improve.dk
Just another mindless drone looking for the perfect stack
posts - 227, comments - 489

AS3 Numbers - get real

Written on June 12, 2008 by Mark S. Rasmussen in Development: AS/Flex/Flash

Skilled developers are hard to come by these days, that includes Flash/AS3/Flex developers. As the product I'm working on is very much dependent on a Flash based frontend, I've been forced to learn & work with AS3 & Flex recently.

It's a great experience, learning a new language - especially now that Silverlight is marching forward. As the old saying goes, know your enemy. Anyways, enough with the chit chatting, on with the problems.

Today I tried making a very simple functionality, I wanted to be able to select a number of images by making them highlight when selected, and dim out when deselected:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute">
	
	<mx:Script>
		<![CDATA[
			private function onClick():void
			{
				if(btnTest.alpha == 0.5)
					btnTest.alpha = 1;
				else
					btnTest.alpha = 0.5;
			}
		]]>
	</mx:Script>
	
	<mx:Button id="btnTest" click="onClick()" label="Click me!"/>
	
</mx:Application>

In this case the button is "selected" from the start (alpha = 1). When clicked, the alpha changes to half opaque (0.5), switches back to 1 when reclicked, and so forth. All working good.

But it's a bit hard to differentiate between selected and non selected, so let's change the alpha setting to 0.4 instead of 0.5:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute">
	
	<mx:Script>
		<![CDATA[
			private function onClick():void
			{
				if(btnTest.alpha == 0.4)
					btnTest.alpha = 1;
				else
					btnTest.alpha = 0.4;
			}
		]]>
	</mx:Script>
	
	<mx:Button id="btnTest" click="onClick()" label="Click me!"/>
	
</mx:Application>

But what's this, now we're only able to dim it, not reselect it. Why's that? Nothing's changed other than the alpha value. The problem becomes apparent if we trace out the buttons alpha value like so:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute">
	
	<mx:Script>
		<![CDATA[
			private function onClick():void
			{
				if(btnTest.alpha == 0.4)
					btnTest.alpha = 1;
				else
					btnTest.alpha = 0.4;
					
				mx.controls.Alert.show(btnTest.alpha.toString());
			}
		]]>
	</mx:Script>
	
	<mx:Button id="btnTest" click="onClick()" label="Click me!"/>
	
</mx:Application>

In case you don't have Flash 9 installed, or are just too lazy to click the button, the resulting Alert box shows the following value: 0.3984375 - obviously not quite the 0.4 we specified.

Ok, let's dumb it down a bit and do some quick testing:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
	initialize="onInitialize()">
	
	<mx:Script>
		<![CDATA[
			
			private function onInitialize():void
			{
				// true
				trace(0.4 == 0.4);
				
				// true
				var zeroPointFour:Number = 0.4;
				trace(zeroPointFour == 0.4);
				
				// true
				var secondZeroPointFour:Number = 0.4;
				trace(zeroPointFour == secondZeroPointFour);
				
				// false
				var testSprite:Sprite = new Sprite();
				testSprite.alpha = 0.4;
				trace(testSprite.alpha == 0.4);
				
				// 0.3984375
				trace(testSprite.alpha);
				
				// false - duh
				trace(0.3984375 == 0.4)
			}
			
		]]>
	</mx:Script>
	
</mx:Application>

Now this is where things start getting weird. We can obviously store the value 0.4 in a number (which is a 64 bit double-precision format according to the IEEE-754 spec). Furthermore, we're also able to compare two instances of Number with the value 0.4 and get the expected equality comparison result, true. Now, it would seem that as soon we set the alpha value on our Sprite, it's corrupted. Sprite inherits the alpha property from DisplayObject - which obviously lists alpha as a value of type Number.

Why does this happen? It's no problem storing the value 0.4 in a 64 bit double precision number:
Sign: +1
Exponent: -2
Mantissa: 1.6
Result: sign x 2exponent x mantissa => +1 x 2-2 x 1.6 = 0.4

It might be (and probably is) me not understanding something right. Can somebody explain to me how the Flash VM handles Numbers, and thereby, explain why this is happening? Is it perhaps not due to the VM's handling of Numbers, but instead just a simple matter of an odd implementation of the alpha property on DisplayObject?

Feedback

Gravatar

Chris Velevitch wrote on 6/15/2008 3:38 PM

The results you're seeing indicates the alpha value is stored as 8 bits:

0.4 = 0.01100110011001100110011001100110011001100110011001101 (64 bit precision)

0.01100110 = 0.3984375
Gravatar

Mark S. Rasmussen wrote on 6/15/2008 4:04 PM

Chris,

Thanks for your comment. Do you know why the alpha is represented as a Number, when it clearly looses precision internally? It's not that I need to represent my alpha values with double precision, I just don't like the design of non-transparent type conversion.
Gravatar

Chris Velevitch wrote on 6/16/2008 12:18 AM

I believe it's for 2 reasons. Firstly, it's not humanly possible to see the difference between alpha values that differ at the 64th bit, and I don't think current technology can generated it. Secondly, alpha values are usually calculated from some geometric or trigometric expression.
Gravatar

Mark S. Rasmussen wrote on 6/16/2008 10:26 PM

Chris,

I do not require my alpha values to be precise to multiple decimals, I don't even need decimal precision - as you say, we won't notice anyways. As for the expression math, that may be, but that does not change that the original input ought maintain it's value while the end result might loose precision.

The thing here is that specifying the alpha value as a Number declares a contract. Whatever you input into my alpha property will be of type Number, and hence act as a number. By silently - somehow - converting the internal representation to only 8 bits, we loose precision - which goes against the Number contract.

Now, AS3 does not - to my knowledge - have an 8bit datatype, so that is out of the question. DisplayObject ought to save the original value as a Number and only use their less precise internal value in internal calculations. If I set my value to X, I should get X back - as long as I do not cross the precision boundaries of the specified type, Number.

This is priggishness, I know, but it's important none the less, imho.
Gravatar

v4corg wrote on 6/7/2009 10:30 AM

to the 8-bit representation: i believe more that the real internally used alpha - value is a simple ubyte (0-255) whichs getter function just "Numbers" it.

Post Comment

Name  
Email
Url
Comment
Please add 6 and 1 and type the answer here: