二进制的世界

来源:互联网 发布:alpha1机器人软件下载 编辑:程序博客网 时间:2024/05/22 06:26

转自answer-huang的博客

正如你所知的那样,电脑的资料都是以二进制存储的,当然我们编程语言中的变量也都是用二进制存储,在Cocoa和iOS编程中大量使用了位运算。通常我们接触的有这几个: <<(左移),>>(右移),&(与),|(或), ^(异或),~(非)。通过这些符号,我们可以对变量进行位元运算。

 
<<和>>
左移和右移的功能是移动变量中所有位元,位元向左/向右移动之后,最高位/最低为的位元会被移除并补0:
5 << 1 = 10  //5的二进制为00101,全部位元向左移动一位数后便会变成 01010
 5 >> 1 = 2    //5的二进制为00101,全部位元向右移动一位数后便会变成 00010
 
•位元:即我们常说的Bit,指二进制中的一位,也称二进制位,是二进制最小信息单位。
 
十进制中,所有位数向左移动一位变为原来的十倍,向右移动一位变为原来的十分之一,二进制中也是如此,向左移动一位会变为原来的两倍,移动两位则变为四倍。对于电脑来说,进行位元运算要比乘除法快不少(在现代架构中, 情况并非如此:位运算的运算速度通常与加法运算相同,仍然快于乘法运算),所以对于性能要求较高的应用中,可以多考虑使用位元运算取代乘除法,但缺点是代码可读性就没那么高了。
 
&
学过C语言的应该都接触过&符号,它能将两个变量对应的位元进行’与’逻辑运算并产生新的变量。最基本的如:
0 & 0 = 0
1 & 0 = 0
0 & 1 = 0
1 & 1 = 1
 
两个相应的二进位都为1, 该位的结果值才为1,否则为0,假设我们现在计算85&109,根据运算规则:
109 -> 1101101
 &85   -> 1010101
 69      = 1000101
 
弄懂这个运算后我们来看一个Cocoa中的一个例子:
UIColor类中,我们不能直接通过颜色的Hex值得到一个UIColor的对象,而PS,Web中都大量的使用Hex值,所以我们需要给UIColor扩展一个Category,这样便可快速根据Hex值生成UIColor对象:
  1. +(UIColor *)colorWithRGBHex:(UInt32)hex alpha:(CGFloat)alpha 
  2.     int r = (hex >> 16) & 0xFF; 
  3.     int g = (hex >> 8) & 0xFF; 
  4.     int b = (hex) & 0xFF; 
  5.     return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:alpha]; 
 
相信很多人都用过这样的方法,但估计很少人去深究这样做的道理,下面我就详细解释一下这其中的原理:
 
1)这个类方法接受两个参数,一个是UInt32类型的hex值(即16进制的颜色值,eg:0xf5c018),CGFloat类型的alpha(即浮点类型的透明度)。
2)根据所给的hex值计算得到r,g,b的值。
3)调用UIColor的类方法colorWithRed:green:blue:alpha:返回一个color对象
 
这个方法的主要都集中在第二步,我们可以看到计算r值时先将hex右移16位,再和0xFF进行&运算。
 
•我们先了解一下hex值,比如0xf5c018代表了红色为f5,绿色为c0,蓝色为18的颜色(均为16进制),每个颜色组件占一个字节即8位(在iOS和OS X上最常见的格式就是大家所熟知的32bits-per-pixel(每个像素占32位),8bits-per-componet(每个颜色组件占8位)),所以这三个颜色总共占了24位(还有8位用来存放透明度)。
 
我们可以将0xffc018转换为二进制:11110101 11000000 00011000,此时我们再看右移16位的操作,你便会发现这个操作执行完后变为:00000000 00000000 11110101,其实是移除了绿色和蓝色的位,最终只剩下红色位上的值,接下来我们用得到的值和0xFF进行&运算:
00000000 00000000 11111111
 & 00000000 00000000 11110101
 ->00000000 00000000 11110101
最终我们把00000000 00000000 11110101赋值给整型r,到此我们便得到红色的值:r=245。
 
同理将hex值右移8位便得到:00000000 11110101 11000000,然后再和0xFF进行&运算:
00000000 00000000 11111111
 &  00000000 11110101 11000000
 ->00000000 00000000 11000000
最终我们把00000000 00000000 11000000赋值给整型g,到此我们便得到绿色的值:g=192。
 
同样的方法得到蓝色:b=24,得到r,g,b后我们便很容易得到UIColor对象了,其实RGB和hex之间转换的原理就是利用了进制的相互转换。
 
另外我们可以用&很容易的判断一个数的奇偶性,因为奇数的二进制最后一位必定为1,所以再和1进行&运算后仍为1,而偶数的二进制最后一位必定为0,所以与1进行&运算为0:
 (n & 1)?奇数:偶数
 
|
|的功能是将两个变量对应的位元进行’或’逻辑运算并产生新的变量。最基本的如:
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
 
两个相应的二进位中只要有一个为1, 该位的结果值为1,假设我们现在计算85|109,根据运算规则:
109  -> 1101101
| 85 -> 1010101
125 =    1111101
 
同样的,我们看Cocoa中的一个例子(Lancy的这篇文章已经讲的比较详细,就直接引用了):
 
  1. typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) { 
  2.     UIViewAnimationOptionLayoutSubviews            = 1 <<  0, 
  3.     UIViewAnimationOptionAllowUserInteraction      = 1 <<  1, // turn on user interaction while animating 
  4.     UIViewAnimationOptionBeginFromCurrentState     = 1 <<  2, // start all views from current value, not initial value 
  5.     UIViewAnimationOptionRepeat                    = 1 <<  3, // repeat animation indefinitely 
  6.     UIViewAnimationOptionAutoreverse               = 1 <<  4, // if repeat, run animation back and forth 
  7.     UIViewAnimationOptionOverrideInheritedDuration = 1 <<  5, // ignore nested duration 
  8.     UIViewAnimationOptionOverrideInheritedCurve    = 1 <<  6, // ignore nested curve 
  9.     UIViewAnimationOptionAllowAnimatedContent      = 1 <<  7, // animate contents (applies to transitions only) 
  10.     UIViewAnimationOptionShowHideTransitionViews   = 1 <<  8, // flip to/from hidden state instead of adding/removing 
  11.     UIViewAnimationOptionOverrideInheritedOptions  = 1 <<  9, // do not inherit any options or animation type 
  12.   
  13.     UIViewAnimationOptionCurveEaseInOut            = 0 << 16, // default 
  14.     UIViewAnimationOptionCurveEaseIn               = 1 << 16, 
  15.     UIViewAnimationOptionCurveEaseOut              = 2 << 16, 
  16.     UIViewAnimationOptionCurveLinear               = 3 << 16, 
  17.   
  18.     UIViewAnimationOptionTransitionNone            = 0 << 20, // default 
  19.     UIViewAnimationOptionTransitionFlipFromLeft    = 1 << 20, 
  20.     UIViewAnimationOptionTransitionFlipFromRight   = 2 << 20, 
  21.     UIViewAnimationOptionTransitionCurlUp          = 3 << 20, 
  22.     UIViewAnimationOptionTransitionCurlDown        = 4 << 20, 
  23.     UIViewAnimationOptionTransitionCrossDissolve   = 5 << 20, 
  24.     UIViewAnimationOptionTransitionFlipFromTop     = 6 << 20, 
  25.     UIViewAnimationOptionTransitionFlipFromBottom  = 7 << 20, 
  26. } NS_ENUM_AVAILABLE_IOS(4_0); 
 
我们观察Apple在UIViewAnimationOptions的枚举变量,使用了一个NSUInteger就表示了UIViewAnimation所需的所有Option。其中0~9十个是互不影响的可同时存在option。16~19,20~24使用了4位来表示互斥的option。
 
如此定义了之后,对UIViewAnimationOptions的赋值变得尤为简单,使用 | 操作符既可以获得一个给对应的option位赋值后的结果。例如:
  1. [UIView animateWithDuration:1.0 
  2.                       delay:0 
  3.                     options:UIViewAnimationOptionAllowUserInteraction 
  4.                          | UIViewAnimationOptionBeginFromCurrentState 
  5.                          | UIViewAnimationOptionCurveEaseIn 
  6.                  animations:{...} 
  7.                  completion:{...}]; 
提取也比较简单,使用 & 操作符 和 >> 操作符,就可以轻松判定某个位有没有被设置,以及提取某些状态位,例如:
 
  1. UIViewAnimationOptions option = UIViewAnimationOptionAllowUserInteraction 
  2.                                 | UIViewAnimationOptionBeginFromCurrentState 
  3.                                 | UIViewAnimationOptionCurveEaseIn 
  4.                                 | UIViewAnimationOptionTransitionCrossDissolve; 
  5.   
  6. if (option & UIViewAnimationOptionAllowUserInteraction) { 
  7.     NSLog(@"UIViewAnimationOptionAllowUserInteraction has been set"); 
  8. if (option & UIViewAnimationOptionBeginFromCurrentState) { 
  9.     NSLog(@"UIViewAnimationOptionBeginFromCurrentState has been set"); 
  10. UInt8 optionCurve = option >> 16 & 0xf; 
  11. if (optionCurve == 1) { 
  12.     NSLog(@"UIViewAnimationOptionCurveEaseIn has been set"); 
  13. UInt8 optionTransition = option >> 20 & 0xf; 
  14. if (optionTransition == 5) { 
  15.     NSLog(@"UIViewAnimationOptionTransitionCrossDissolve has been set"); 
 
这里最需要注意的地方就是,对互斥的状态的设置必须尤为小心,如果你这么写:
  1. UIViewAnimationOptions badOption = UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionCurveEaseOut; 
  2. UInt8 oops = badOption >> 16 & 0xf; 
  3. NSLog(@"Sorry, it's not UIViewAnimationOptionCurveEaseInOut"); 
  4. NSLog(@"oops = %d, you got UIViewAnimationOptionCurveLinear", oops); 
 
^
^的功能是将两个变量对应的位元进行’异或’逻辑运算并产生新的变量。最基本的如:
0 ^ 0 = 0
 0 ^ 1 = 1
 1 ^ 0 = 1
 1 ^ 1 = 0
 
简言之就是两个比较的位不同时才为1,相同则为0。Cocoa中^有特定的用意(block中),所以别的场合中很少用到,这里我想到一个比较经典但不常见的例子:
 
写程序时有时要交换两个变量的值,通常的做法是定义一个中间变量,从而将两个变量的值进行交换,而我们其实可以使用^运算符直接将两个变量进行交换:
a = a ^ b;
b = a ^ b;
a = a ^ b;
 
乍眼看去可能看不出什么,我们不妨假设sum=a^b。
 
 第二步中的a替换成sum就得到b=sum^b=a^b^b=a。
 
 第三步中的a和b同时替换掉前两步中的值就得到a=a^b^a=b。
 
 最终顺利交换两个变量的值。
 
•对于a^b^b,我们可以先计算b^b,因为所有位元都相同,所以b^b=0,然后再计算a^0,因为1^0=1,0^0=0,所以a^0=a。
 
~
~ 0 = 1
 ~ 1 = 0
 ~的作用是将变量的每一个位元都颠倒过来,比如:
~00000000 00000000 00000000 00000101 -> 5
 =11111111 11111111 11111111 11111010 ->-6
0 0
原创粉丝点击