在ActionScript中,对数值的某些位操作可以显著提高运算效率,下面就与大家分享我工作中常用的和不常用的以及刚学习到的一些位操作知识。
1.字节与位
1个字节(byte)=8个二进制位(bitwise)
2.有符号整数和无符号整数
我们知道在计算机里面,以二进制存储着一个数值,在这个二进制数中最左边的一位一般用来表示正数还是负数。0表示正数,1表示负数。一个8位无符号整数的取值范围是0~2^8-1(2的8次方减1),而一个8位有符号整数的取值范围是-2^7~2^7-1,因为最左边1位是作为标示位来标示正数还是负数,有效计算大小的只是后面的7位。
3.按位和按位组合赋值
(注意:as3中没有<<<)
4. &操作
var a:int = 13; var b:int = 11; trace(a & b); //9
A.判断奇偶
依据:偶数的二进制末尾是0,与1进行按位与,结果为0.奇数的二进制末尾是1,与1进行按位与,结果为1.
//判断奇偶 var a:int = int(Math.random() * 1000); if(a & 1){ trace(a + "是奇数"); }else{ trace(a + "是偶数"); }
B.快速取模运算
当a%b,b是2^n的时候,可以写成a&(2^n-1)
5.|操作
var a:int = 13; var b:int = 11; trace(a | b); //15
关于&与|在程序设计中有个妙用,就是用来判断是否具备某个属性,以及用来生成一条记录,满足若干属性。
这一点我举个例子说明:
写个很简单的c语言例子,以前写的顺便黏贴了过来:
#include <stdio.h> int main() { unsigned int i; unsigned int boy = 1; //0x01 unsigned int girl = 2;//0x02 unsigned int music = 4;//0x04 unsigned int game = 8;//0x08 unsigned int travel = 16;//0x10 unsigned int read = 32;//0x20 //逻辑或:用于记录生成男孩+游戏+旅行 unsigned int test2 = boy | game | travel; //逻辑或:用于记录生成女孩+音乐+旅行 unsigned int test = girl | music | travel; //逻辑与:判断是否满足某种条件 if((test & boy) == boy){ printf("test is a boy\n"); }else{ printf("test is a girl\n"); } if((test & music) == music){ printf("test loves music\n"); }else{ printf("test doesn't love music\n"); } if(((test & girl) == girl) && ((test & game) != game)){ printf("test is a girl and she doesn't love game.\n"); } getchar(); }
通常的做法是把一些互相排斥没有交集的一些属性定义为2^n,
如1、2、4、8、16、32或者写成0x01、0x02、0x04、0x08、0x10、0x20或者1<<0、1<<1、1<<2、1<<3、1 << 4、1 << 5等,
var a:int = 1 << 0;//var a:int = 1; var b:int = 1 << 1;//var b:int = 2; var c:int = 1 << 2;//var c:int = 4; var d:int = 1 << 3;//var d:int = 8;
如果一个对象的某个属性(x & a) == a,则该对象具有a属性,如果某个对象的属性y = a | b | c | d,则该对象则具有abcd四个属性。
//注:这里注意(x & a) == a中, & 和 == 的优先级关系,==的优先级大于&,故要括弧起来。感谢26楼yangzhiyong的提醒。
关于&|的用法,这里只是抛砖引玉,相信你们有更妙的用法~~~
6. << 和 >>
A.倍数问题
a * 2 == a << 1; a * 4 == a << 2; a * 8 == a << 3; a * 16 == a << 4; a * 32 == a << 5;
a / 2 == a >> 1; a / 4 == a >> 2; a / 8 == a >> 3; a / 16 == a >> 4; a /32 == a >> 5;B.取整
3.14159 >> 0 == 3; 3.14159 << 0 == 3;浮点数通过<<或者>>舍去小数点后面的所有位来转换为整数。 左移0位或者右移0位相当于取整运算。
C.颜色的相关操作
//产生随机颜色 var r:int=Math.round(Math.random()*255); var g:int=Math.round(Math.random()*255); var b:int=Math.round(Math.random()*255); trace(r + "," + g +"," + b) var col:Number = r << 16 | g << 8 | b;//通过按位操作,获取颜色值 //创建显示对象 var sp:Sprite=new Sprite(); sp.graphics.beginFill(col); sp.graphics.drawCircle(60,60,50); sp.graphics.endFill(); addChild(sp);
我们随便给一个颜色值,比如1个24位颜色值,用16进制表示,随便取个吧,如0x342388,那么很显然红色字节表示的大小是34(16进制中的34),绿色字节表示的大小是23,蓝色字节表示的大小是88,我们可以把0x342388理解成0x340000 | 0x002300 | 0x000088。我们解析下上面那段程序:
var r:int=Math.round(Math.random()*255); var g:int=Math.round(Math.random()*255); var b:int=Math.round(Math.random()*255);这3行用来随机生成红绿蓝三种色数值,由于红绿蓝都是1个字节,有8位,取值范围为0~2^8-1即0~255,所以不难理解。
r = 34;
g = 23;
b = 88;
而通过这3个数值组成一个颜色值,需要r的二进制向左移动16位,r << 16, g的二进制向左移动8位,而b的二进制则不需要移位操作。
那32位颜色的合成和24位基本相同,只是多了透明度:
var alpha:uint = 0x22; var r:uint = 0x34; var g:uint = 0x23; var b:uint = 0x88; var color:uint = alpha << 24 | r << 16 | g << 8 | b;
现在我们知道了rgb的16进制值,那反过来呢?如果我们知道了一个颜色值,如何反向求解rgb值呢?
var color:uint = 0x342388; var r:uint = color >> 16;//右移16位,把2388移出,取0x34 var g:uint = color >> 8 & 0xff;//右移8位,把88移出,得0x3423,与0xff按位与操作,得0x23 var b:uint = color & 0xff;//得到0x88我们再来看看32位的:
var color:uint = 0xff342388; var a:uint = color >>> 24 //注意这里是>>>,无符号右移位操作,右移24位,把342388移出,得到0xff var r:uint = color >> 16 & 0xff;//右移16位,把2388移出,取0x34 var g:uint = color >> 8 & 0xff;//右移8位,把88移出,得0x3423,与0xff按位与操作,得0x23 var b:uint = color & 0xff;//得到0x88
7.>>>无符号右移位操作
as3中没有<<<无符号左移位操作符,那>>>与>>的区别在哪???
我们举个例子:比如一个透明度为1的一个黑色,用16进制表示的32位颜色为0xff000000,那其实二进制是
1111 1111 0000 0000 0000 0000 0000 0000 color
1111 1111 1111 1111 1111 1111 1111 1111 color >>24结果
0000 0000 0000 0000 0000 0000 1111 1111 color >>>24结果
对比可以发现:
var a:uint = color >>> 24 //注意这里是>>>,无符号右移位操作,右移24位,把342388移出,得到0xff
8.~和^
A. 取绝对值
(x ^ (x >> 31)) – (x >> 31);B.交换数值
var k:int = a; a = b; b = k; /*等价于*/ a ^= b; b ^= a; a ^= b;
如果有错误欢迎朋友指出,转载请注明出处:http://my.oschina.net/game007