在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.按位和按位组合赋值
- & (bitwise AND)将expression1和expression2转换为 32 位无符号整数,并对整数参数的每一位执行布尔 AND 运算。
- | (bitwise OR)将expression1和expression2转换为 32 位无符号整数,并在expression1或expression2的对应位为 1 的每个位的位置上放置 1。
- ~ (bitwise NOT)将expression转换为一个 32 位带符号整数,然后按位对 1 求补。
- ^ (bitwise XOR)将expression1和expression2转换为 32 位无符号整数,并在expression1或expression2中对应位为 1(但不是在两者中均为 1)的每个位的位置上放置 1。
- << (bitwise left shift)将expression1和shiftCount转换为 32 位整数,并将expression1中的所有位向左移动由shiftCount转换所得到的整数指定的位数。
- >> (bitwise right shift)将expression和shiftCount转换为 32 位整数,并将expression中的所有位向右移动由shiftCount转换所得到的整数指定的位数。
- >>> (bitwise unsigned right shift)此运算符与按位向右移位运算符 (>>) 基本相同,只是此运算符不保留原始表达式的符号,因为左侧的位始终用 0 填充。
(注意:as3中没有<<<)
- &= (bitwise AND assignment)对expression1赋予expression1& expression2的值。
- |= (bitwise OR assignment)对expression1赋予expression1 / expression2的值。
- ^= (bitwise XOR assignment)对expression1赋予expression1 ^ expression2的值。
- <<= (bitwise left shift and assignment)执行按位向左移位 (<<=) 运算,并将内容作为结果存储在expression1中。
- >>= (bitwise right shift and assignment)执行按位向右移位运算,并将结果存储在expression中。
- >>>= (bitwise unsigned right shift and assignment)执行无符号按位向右移位运算,并将结果存储在expression中。
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)
- a % 8
- a&7
- a%16
- a&15
- a%256
- a&255
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结果
对比可以发现:
- >>:当color的最高有效位(最左端的位)为 0 时,左侧的位都填补 0;如果最高有效位为 1,左侧的位都填补 1。
- >>>:此运算符与按位向右移位运算符(>>)基本相同,只是>>>不保留原始表达式的符号,因为左侧的位始终用 0 填充。
- 这就是下行代码为何用>>>的原因
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;
按位异或:11为0,10为1,00为0。那么同一个数对另一个数进行2次按位抑或,仍然是本身。
如果有错误欢迎朋友指出,转载请注明出处:http://my.oschina.net/game007