概述
Representing Binary Numbers
Computers operate on 1's and 0's; these are called 'bits'. A byte is a group of 8 bits, like this example: 00110101. A computer word on a 32-bit computer ('int') is 4 bytes, 32 bits: 10011010110101011010001010101011. Other computers have different word sizes; over time, 64-bit integers will become more common.
As you can see, 32 ones and zeroes is a bit cumbersome to write down (or even to read). Thus, people conventionally break these large numbers of digits down into groups of 3 or 4 bits:
1001.1010.1101.0101.1010.0010.1010.1011 <-- four bit groups 10.011.010.110.101.011.010.001.010.101.011 <-- three bit groups (note that the count of 3 starts on the right)
These grouped sets of bits are then mapped onto digits, either four bits per hexadecimal (base 16) digit or three bits per octal (base 8) digit. Obviously, hexadecimal needs some new digits (since decimal digits only go 0..9 and 6 more are needed). These days, the letters 'A'..'F' are used for the 'digits' that represent 10..15. Here's the map; the correspondence is obvious:
OCTAL: HEXADECIMAL: 000 -> 0 100 -> 4 0000 -> 0 0100 -> 4 1000 -> 8 1100 -> C 001 -> 1 101 -> 5 0001 -> 1 0101 -> 5 1001 -> 9 1101 -> D 010 -> 2 110 -> 6 0010 -> 2 0110 -> 6 1010 -> A 1110 -> E 011 -> 3 111 -> 7 0011 -> 3 0111 -> 7 1011 -> B 1111 -> F (both upper and lower case A-F are used across different computers and operating systems).
The hex and octal representations of those integers above are easy to translate from the binary counterparts; add 0x to the front for a C-style-language hexadecimal number that the compiler will accept:
1001.1010.1101.0101.1010.0010.1010.1011 -> 9 A D 5 A 2 A B --> 0x9AD5A2AB (that's 0x in front of the hex number)and
10.011.010.110.101.011.010.001.010.101.011 2 3 2 6 5 3 2 1 2 5 3 -> 023265321253 (that's a numeric '0' in front)
Octal is easier to write down quickly, but hexadecimal has the nice properties of breaking easily into bytes (which are pairs of hexadecimal digits).
Some aids for remembering the correspondence of hexadecimal (often called 'hex') digits and their decimal digit counterpart:
- hex 0-9 are the same as decimal digits 0-9
- A is the first one past 9 and is easy to remember as 10
- F is the last one and thus easy to remember as 15
- C is decimal 12 (the only one that you sort of have to memorize)
- All the rest are close to A, C, or F (B is just A+1, D is C+1, E is F-1)
If someone mentions the "third bit" of a number, its best to find out if they mean third bit from the left or from the right and whether they start counting from 0 or 1. A miscommunication can result in real problems laster on (i.e., reversed strings of bits!).This page, for example, starts counting with the rightmost bit being number 1. This pageis a gem in that answer 5 counts from the right starting at 1, while answer 8 counts from the right starting at 0.
Almost all modern computers use the left-most bit as the 'sign bit' which signifies a negative integer if its value is 1. Note that identifying the location of the sign bit requires knowledge of precisely how many bits are in a given data type. This number can change over time (i.e., when you recompile on a different computer). Generally, the sizeof() operator will tell you the number of bytes (which are generally 8 bits) its argument contains, e.g., sizeof(int) or sizeof (100) will yield 4 on a 32-bit machine. Sometimes one can identify a system-based include file that contains the proper constants if a program must depend on a certain word (integer) length.
Operating on Binary Numbers in Programs
Sometimes it is handy to work with the bits stored in numbers rather than just treating them as integers. Examples of such times include remembering choices (each bit slot can be a 'yes'/'no' indicator), keeping track of option flags (same idea, really, each bit slot is a 'yes'/'no' indicator for a flag's presence), or keeping track of a number of small integers (e.g., successive pairs of bit slots can remember numbers from 0..3). Of course, occasionally programming tasks actually contain 'bit strings'.
In C/C++ and others, assigning a binary number is easy if you know its octal or hexadecimal representation:
i = 0x9AD5A2AB; /* hexadecimal: 0x */or
i = 023265321253; /* octal: start with 0 */
More often, a pair of single-bit valued integers is combined to create an integer of interest. One might think the statement below would do that:
i = 0x10000 + 0x100;and it will -- until the sign bit enters the picture or the same bit is combined twice:
i = 0x100 + 0x100;
In that case, a 'carry' occurs (0x100 + 0x100 = 0x200 which is probably not the result you want) and then i contains 0x200 instead of 0x100 as probably desired. The 'or' operation -- denoted as '|' in C/C++ and others -- does the right thing. It combines corresponding bits in its two operands using these four rules:
0 | 0 -> 0 0 | 1 -> 1 1 | 0 -> 1 1 | 1 -> 1The '|' operation is called 'bitwise or' in C so as not to be confused with it's cousin '||' called 'logical or' or 'orif'. The '||' operator evaluates the arithmetic value of its left side operand and, if that value is false (exactly 0), it evaluates its right side operand. The 'orif' operator is different: if either operand is nonzero, then '||' evaluates to true (exactly 1 in C).
It is "1 | 1 = 1" that distinguishes the '|' operator from '+'. Sometimes operators like this are displayed as a 'truth table':
right operand operator | | 0 1 ---+------ left 0 | 0 1 <-- results operand 1 | 1 1 <-- results
It's easy to see that the 'bitwise or' operation is a way to set bits inside an integer. A '1' results with either or both of the input bits are '1'.
The easy way to query bits is using the 'logical and' (also known as 'bitwise and') operator which is denoted as '&' and has this truth table:
& | 0 1 ---+------ 0 | 0 0 1 | 0 1Do not confuse the single '&' operator with its partner named 'andif' with two ampersands ('&&'). The 'andif' operator will evaluate its left side and yield 0 if the left side is false, without evaluating its right side operand. Only if the left side is true will the right side be evaluated, and the result of the operator is the logical 'and' of their truth values (just as above) and is evaluated to either the integer 0 or the integer 1 (vs. '&' which would yield 4 when evaluating binary 100100 & 000111).
A '1' results only when *both* input bits are '1'. So, if a program wishes to know if the 0x100 bit is '1' in an integer, the if statement is simple:
if (a & 0x100) { printf("yes, 0x100 is onn"); }C/C++ (and others) contain additional operators, including 'exclusive or' (denoted '^') with this truth table:
^ | 0 1 ---+------ 0 | 0 1 1 | 1 0
The 'exclusive or' operator is sometimes called 'xor', for easy of typing. Xor yields a '1' either exactly *one* of its inputs is one: either one or the other, but not both. This operator is very handy for 'toggling' (flipping) bits, changing them from '1' to '0' or vice-versa. Consider this statement:
a = a ^ 0x100; /* same as a ^= 0x100; */The 0x100 bit will be changed from 0->1 or 1->0, depending on its current value.
Switching off a bit requires two operators. The new one is the unary operator that toggles every bit in a word, creating what is called the 'bitwise complement' or just 'complement' of a word. Sometimes this is called 'bit inversion' or just 'inversion' and is denoted by the tilde: '~'. Here's a quick example:
char a, b; /* eight bits, not 32 or 64 */ a = 0x4A; /* binary 0100.1010 */ b = ~a; /* flip every bit: 1011.0101 */ printf("b is 0x%Xn", b);which yields:
b is 0xB5
Thus, if we have a single bit switched on (e.g., 0x100) then ~0x100 has all but one bit switched on: 0xFFFFFEFF (note the 'E' as the third 'digit' from the right) (this example shows a 32-bit value; a 64-bit value would have a lot more F's on the front).
These two operators combine to create a scheme for switching off bits:
a = a & (~0x100); /* switch off the 0x100 bit */ /* same as a &= ~0x100;since all but one bit in ~0x100 is on, all the bits except the 0x100 bits appear in the result. Since the 0x100 bit is 'off' in ~0x100, that bit is guaranteed to be '0' in the result. This operation is universally called 'masking' as in 'mask off the 0x100 bit'.
Summary
In summary, these operators enable setting, clearing, toggling, and testing any bit or combination of bits in an integer:
a |= 0x20; /* turn on bit 0x20 */ a &= ~0x20; /* turn off bit 0x20 */ a ^= 0x20; /* toggle bit 0x20 */ if (a & 0x20) { /* then the 0x20 bit is on */ }
Shifting
Moving bits to the left or right is called 'shift'ing. Consider a five-bit binary number like 00110. If that number is shifted one bit left, it becomes: 01100. On the other hand, if 00110 is shift one bit to the right, it becomes 000011. Mathematically inclined users will realize that shifting to the left one bit is the same as multiplying by 2 while shifting to the right one bit is usually the same as an integer divide by 2 (i.e., one discards any remainder). Why usually? Shifting -1 right by one yields an unusual result (i.e,, 0xFFFF.FFFF >> 1 == 0xFFFF.FFFF, no change at all).
Generally, one can specify a shift by more than one bit: Shifting 000001 to the left by three bits yields 001000. The shift operators are:
a << n /* shift a left n bits a >> n /* shift a right n bitsOne generally shifts integers (instead of floating-point numbers),although nothing prevents shifting floating point numbers in somelanguages. The results are generally very difficult to interpret as afloating point number, of course.
When shifting to the left, 0's are inserted in the lower end.When shifting to the right, the high order bit is duplicatedand inserted for the newly-needed bit (thus preserving the number's sign).This means that (-1)>>1 yields -1 instead of 0!
Another type of shift, unavailable natively in most programminglanguages is the 'circular' shift, where bits shifted off one endare inserted at the other end instead of the default 0. Modernuses of this operation are rare but could appear occasionally. Somemachines (e.g., the x86 architecture) have assembly-languageinstructions for this, but the prudent C or Java programming willspend a few more machine cycles (billionths of a second) to executeboth a shift and then a bit-extract-shift-or combination to movethe bit themselves.
A note on optimization: some zealous optimizing coders like to changea/4 to '(a>>2)' in order to save time ("since multiplies can beslow"). Modern compilers know all about this and perform suchsubstitutions automatically, thus leaving the better programmer towrite a/4 when that is what's meant.
Very Advanced Bit Manipulation
Skip this section if this is your first time dealing with bits.Read it at your leisure in the future after you've written some bitmanipulation code. Really.
It turns out that the way 2's complement machines represent integersand the way they implement subtraction (the standard on virtuallyall modern machines) yields some very interesting possibilities forbit manipulation.
Two's complement machines represent positive integers as the binaryrepresentation of that integer with a 0 in the sign bit. A negativeinteger is represented as the complement of the positive integer(including turning on the sign bit) plus 1. Thus, the absolute valueof the most negative representable integer is one more than themost positive representable integer. Thus:
x +x in 8-bit binary -x in 8-bit binary 0 0000 0000 0000 0000 1 0000 0001 1111 1111 2 0000 0010 1111 1110 3 0000 0011 1111 1101 64 0100 0000 1100 0000 65 0100 0001 1011 1111 126 0111 1110 1000 0010 127 0111 1111 1000 0001 128 [no representation] 1000 0000
Given this representation, addition can proceed just as on penciland paper, discard any extra high order bits that exceed the lengthof the representation. Subtracting b from a (a-b) proceeds as adda and the quantity (-b).
This means that certain bit operations can exploit these definitionsof negation and subtraction to yield interesting results, the proofsof which are left to the reader (see a table ofthese offsite):
Binary Value Sample Meaning x 00101100 the original x value x & -x 00000100 extract lowest bit set x | -x 11111100 create mask for lowest-set-bit & bits to its left x ^ -x 11111000 create mask bits to left of lowest bit set x & (x-1) 00101000 strip off lowest bit set --> useful to process words in O(bits set) instead of O(nbits in a word) x | (x-1) 00101111 fill in all bits below lowest bit set x ^ (x-1) 00000111 create mask for lowest-set-bit & bits to its right ~x & (x-1) 00000011 create mask for bits to right of lowest bit set x | (x+1) 00101101 toggle lowest zero bit x / (x&-x) 00001011 shift number right so lowest set bit is at bit 0There's no reason to memorize these expressions, but rather rememberwhat's possible to refer back to this page for saving time when youprocessing bits.
Representing Binary Numbers
Computers operate on 1's and 0's; these are called 'bits'. A byte is a group of 8 bits, like this example: 00110101. A computer word on a 32-bit computer ('int') is 4 bytes, 32 bits: 10011010110101011010001010101011. Other computers have different word sizes; over time, 64-bit integers will become more common.
As you can see, 32 ones and zeroes is a bit cumbersome to write down (or even to read). Thus, people conventionally break these large numbers of digits down into groups of 3 or 4 bits:
1001.1010.1101.0101.1010.0010.1010.1011 <-- four bit groups 10.011.010.110.101.011.010.001.010.101.011 <-- three bit groups (note that the count of 3 starts on the right)
These grouped sets of bits are then mapped onto digits, either four bits per hexadecimal (base 16) digit or three bits per octal (base 8) digit. Obviously, hexadecimal needs some new digits (since decimal digits only go 0..9 and 6 more are needed). These days, the letters 'A'..'F' are used for the 'digits' that represent 10..15. Here's the map; the correspondence is obvious:
OCTAL: HEXADECIMAL: 000 -> 0 100 -> 4 0000 -> 0 0100 -> 4 1000 -> 8 1100 -> C 001 -> 1 101 -> 5 0001 -> 1 0101 -> 5 1001 -> 9 1101 -> D 010 -> 2 110 -> 6 0010 -> 2 0110 -> 6 1010 -> A 1110 -> E 011 -> 3 111 -> 7 0011 -> 3 0111 -> 7 1011 -> B 1111 -> F (both upper and lower case A-F are used across different computers and operating systems).
The hex and octal representations of those integers above are easy to translate from the binary counterparts; add 0x to the front for a C-style-language hexadecimal number that the compiler will accept:
1001.1010.1101.0101.1010.0010.1010.1011 -> 9 A D 5 A 2 A B --> 0x9AD5A2AB (that's 0x in front of the hex number)and
10.011.010.110.101.011.010.001.010.101.011 2 3 2 6 5 3 2 1 2 5 3 -> 023265321253 (that's a numeric '0' in front)
Octal is easier to write down quickly, but hexadecimal has the nice properties of breaking easily into bytes (which are pairs of hexadecimal digits).
Some aids for remembering the correspondence of hexadecimal (often called 'hex') digits and their decimal digit counterpart:
- hex 0-9 are the same as decimal digits 0-9
- A is the first one past 9 and is easy to remember as 10
- F is the last one and thus easy to remember as 15
- C is decimal 12 (the only one that you sort of have to memorize)
- All the rest are close to A, C, or F (B is just A+1, D is C+1, E is F-1)
If someone mentions the "third bit" of a number, its best to find out if they mean third bit from the left or from the right and whether they start counting from 0 or 1. A miscommunication can result in real problems laster on (i.e., reversed strings of bits!).This page, for example, starts counting with the rightmost bit being number 1. This pageis a gem in that answer 5 counts from the right starting at 1, while answer 8 counts from the right starting at 0.
Almost all modern computers use the left-most bit as the 'sign bit' which signifies a negative integer if its value is 1. Note that identifying the location of the sign bit requires knowledge of precisely how many bits are in a given data type. This number can change over time (i.e., when you recompile on a different computer). Generally, the sizeof() operator will tell you the number of bytes (which are generally 8 bits) its argument contains, e.g., sizeof(int) or sizeof (100) will yield 4 on a 32-bit machine. Sometimes one can identify a system-based include file that contains the proper constants if a program must depend on a certain word (integer) length.
Operating on Binary Numbers in Programs
Sometimes it is handy to work with the bits stored in numbers rather than just treating them as integers. Examples of such times include remembering choices (each bit slot can be a 'yes'/'no' indicator), keeping track of option flags (same idea, really, each bit slot is a 'yes'/'no' indicator for a flag's presence), or keeping track of a number of small integers (e.g., successive pairs of bit slots can remember numbers from 0..3). Of course, occasionally programming tasks actually contain 'bit strings'.
In C/C++ and others, assigning a binary number is easy if you know its octal or hexadecimal representation:
i = 0x9AD5A2AB; /* hexadecimal: 0x */or
i = 023265321253; /* octal: start with 0 */
More often, a pair of single-bit valued integers is combined to create an integer of interest. One might think the statement below would do that:
i = 0x10000 + 0x100;and it will -- until the sign bit enters the picture or the same bit is combined twice:
i = 0x100 + 0x100;
In that case, a 'carry' occurs (0x100 + 0x100 = 0x200 which is probably not the result you want) and then i contains 0x200 instead of 0x100 as probably desired. The 'or' operation -- denoted as '|' in C/C++ and others -- does the right thing. It combines corresponding bits in its two operands using these four rules:
0 | 0 -> 0 0 | 1 -> 1 1 | 0 -> 1 1 | 1 -> 1The '|' operation is called 'bitwise or' in C so as not to be confused with it's cousin '||' called 'logical or' or 'orif'. The '||' operator evaluates the arithmetic value of its left side operand and, if that value is false (exactly 0), it evaluates its right side operand. The 'orif' operator is different: if either operand is nonzero, then '||' evaluates to true (exactly 1 in C).
It is "1 | 1 = 1" that distinguishes the '|' operator from '+'. Sometimes operators like this are displayed as a 'truth table':
right operand operator | | 0 1 ---+------ left 0 | 0 1 <-- results operand 1 | 1 1 <-- results
It's easy to see that the 'bitwise or' operation is a way to set bits inside an integer. A '1' results with either or both of the input bits are '1'.
The easy way to query bits is using the 'logical and' (also known as 'bitwise and') operator which is denoted as '&' and has this truth table:
& | 0 1 ---+------ 0 | 0 0 1 | 0 1Do not confuse the single '&' operator with its partner named 'andif' with two ampersands ('&&'). The 'andif' operator will evaluate its left side and yield 0 if the left side is false, without evaluating its right side operand. Only if the left side is true will the right side be evaluated, and the result of the operator is the logical 'and' of their truth values (just as above) and is evaluated to either the integer 0 or the integer 1 (vs. '&' which would yield 4 when evaluating binary 100100 & 000111).
A '1' results only when *both* input bits are '1'. So, if a program wishes to know if the 0x100 bit is '1' in an integer, the if statement is simple:
if (a & 0x100) { printf("yes, 0x100 is onn"); }C/C++ (and others) contain additional operators, including 'exclusive or' (denoted '^') with this truth table:
^ | 0 1 ---+------ 0 | 0 1 1 | 1 0
The 'exclusive or' operator is sometimes called 'xor', for easy of typing. Xor yields a '1' either exactly *one* of its inputs is one: either one or the other, but not both. This operator is very handy for 'toggling' (flipping) bits, changing them from '1' to '0' or vice-versa. Consider this statement:
a = a ^ 0x100; /* same as a ^= 0x100; */The 0x100 bit will be changed from 0->1 or 1->0, depending on its current value.
Switching off a bit requires two operators. The new one is the unary operator that toggles every bit in a word, creating what is called the 'bitwise complement' or just 'complement' of a word. Sometimes this is called 'bit inversion' or just 'inversion' and is denoted by the tilde: '~'. Here's a quick example:
char a, b; /* eight bits, not 32 or 64 */ a = 0x4A; /* binary 0100.1010 */ b = ~a; /* flip every bit: 1011.0101 */ printf("b is 0x%Xn", b);which yields:
b is 0xB5
Thus, if we have a single bit switched on (e.g., 0x100) then ~0x100 has all but one bit switched on: 0xFFFFFEFF (note the 'E' as the third 'digit' from the right) (this example shows a 32-bit value; a 64-bit value would have a lot more F's on the front).
These two operators combine to create a scheme for switching off bits:
a = a & (~0x100); /* switch off the 0x100 bit */ /* same as a &= ~0x100;since all but one bit in ~0x100 is on, all the bits except the 0x100 bits appear in the result. Since the 0x100 bit is 'off' in ~0x100, that bit is guaranteed to be '0' in the result. This operation is universally called 'masking' as in 'mask off the 0x100 bit'.
Summary
In summary, these operators enable setting, clearing, toggling, and testing any bit or combination of bits in an integer:
a |= 0x20; /* turn on bit 0x20 */ a &= ~0x20; /* turn off bit 0x20 */ a ^= 0x20; /* toggle bit 0x20 */ if (a & 0x20) { /* then the 0x20 bit is on */ }
Shifting
Moving bits to the left or right is called 'shift'ing. Consider a five-bit binary number like 00110. If that number is shifted one bit left, it becomes: 01100. On the other hand, if 00110 is shift one bit to the right, it becomes 000011. Mathematically inclined users will realize that shifting to the left one bit is the same as multiplying by 2 while shifting to the right one bit is usually the same as an integer divide by 2 (i.e., one discards any remainder). Why usually? Shifting -1 right by one yields an unusual result (i.e,, 0xFFFF.FFFF >> 1 == 0xFFFF.FFFF, no change at all).
Generally, one can specify a shift by more than one bit: Shifting 000001 to the left by three bits yields 001000. The shift operators are:
a << n /* shift a left n bits a >> n /* shift a right n bitsOne generally shifts integers (instead of floating-point numbers),although nothing prevents shifting floating point numbers in somelanguages. The results are generally very difficult to interpret as afloating point number, of course.
When shifting to the left, 0's are inserted in the lower end.When shifting to the right, the high order bit is duplicatedand inserted for the newly-needed bit (thus preserving the number's sign).This means that (-1)>>1 yields -1 instead of 0!
Another type of shift, unavailable natively in most programminglanguages is the 'circular' shift, where bits shifted off one endare inserted at the other end instead of the default 0. Modernuses of this operation are rare but could appear occasionally. Somemachines (e.g., the x86 architecture) have assembly-languageinstructions for this, but the prudent C or Java programming willspend a few more machine cycles (billionths of a second) to executeboth a shift and then a bit-extract-shift-or combination to movethe bit themselves.
A note on optimization: some zealous optimizing coders like to changea/4 to '(a>>2)' in order to save time ("since multiplies can beslow"). Modern compilers know all about this and perform suchsubstitutions automatically, thus leaving the better programmer towrite a/4 when that is what's meant.
Very Advanced Bit Manipulation
Skip this section if this is your first time dealing with bits.Read it at your leisure in the future after you've written some bitmanipulation code. Really.
It turns out that the way 2's complement machines represent integersand the way they implement subtraction (the standard on virtuallyall modern machines) yields some very interesting possibilities forbit manipulation.
Two's complement machines represent positive integers as the binaryrepresentation of that integer with a 0 in the sign bit. A negativeinteger is represented as the complement of the positive integer(including turning on the sign bit) plus 1. Thus, the absolute valueof the most negative representable integer is one more than themost positive representable integer. Thus:
x +x in 8-bit binary -x in 8-bit binary 0 0000 0000 0000 0000 1 0000 0001 1111 1111 2 0000 0010 1111 1110 3 0000 0011 1111 1101 64 0100 0000 1100 0000 65 0100 0001 1011 1111 126 0111 1110 1000 0010 127 0111 1111 1000 0001 128 [no representation] 1000 0000
Given this representation, addition can proceed just as on penciland paper, discard any extra high order bits that exceed the lengthof the representation. Subtracting b from a (a-b) proceeds as adda and the quantity (-b).
This means that certain bit operations can exploit these definitionsof negation and subtraction to yield interesting results, the proofsof which are left to the reader (see a table ofthese offsite):
Binary Value Sample Meaning x 00101100 the original x value x & -x 00000100 extract lowest bit set x | -x 11111100 create mask for lowest-set-bit & bits to its left x ^ -x 11111000 create mask bits to left of lowest bit set x & (x-1) 00101000 strip off lowest bit set --> useful to process words in O(bits set) instead of O(nbits in a word) x | (x-1) 00101111 fill in all bits below lowest bit set x ^ (x-1) 00000111 create mask for lowest-set-bit & bits to its right ~x & (x-1) 00000011 create mask for bits to right of lowest bit set x | (x+1) 00101101 toggle lowest zero bit x / (x&-x) 00001011 shift number right so lowest set bit is at bit 0There's no reason to memorize these expressions, but rather rememberwhat's possible to refer back to this page for saving time when youprocessing bits.
代表二进制数
计算机运行在1和0; 这些被称为'位'。字节是一组8位,如下例所示:00110101。32位计算机上的计算机字('int')是4字节,32位:10011010110101011010001010101011。其他计算机具有不同的字大小; 随着时间的推移,64位整数将变得更加普遍。
正如您所看到的,32个零和0写下来(甚至读取)有点麻烦。因此,人们通常将这些大量的数字分成3或4位的组:
1001.1010.1101.0101.1010.0010.1010.1011 < - 四位组 10.011.010.110.101.011.010.001.010.101.011 < - 三位组 (注意右边3个开头的数量)
然后将这些分组的比特组映射到数字上,每十六进制(基数16)数字为4比特,或每八进制数(基数8)数字为3比特。显然,十六进制需要一些新的数字(因为十进制数字只需要0..9,还需要6个数字)。这些天,字母'A'..'F'用于表示10..15的'数字'。这是地图; 通信很明显:
OCTAL:HEXADECIMAL: 000 - > 0 100 - > 4 0000 - > 0 0100 - > 4 1000 - > 8 1100 - > C. 001 - > 1 101 - > 5 0001 - > 1 0101 - > 5 1001 - > 9 1101 - > D. 010 - > 2 110 - > 6 0010 - > 2 0110 - > 6 1010 - > A 1110 - > E. 011 - > 3 111 - > 7 0011 - > 3 0111 - > 7 1011 - > B 1111 - > F. (大写和小写AF都用于不同的计算机和 操作系统)。
上面那些整数的十六进制和八进制表示很容易从二进制对应物中转换出来; 在前面添加0x,以获得编译器将接受的C样式语言十六进制数:
1001.1010.1101.0101.1010.0010.1010.1011 - > 9 AD 5 A 2 AB - > 0x9AD5A2AB (在十六进制数字前面是0x)和
10.011.010.110.101.011.010.001.010.101.011 2 3 2 6 5 3 2 1 2 5 3 - > 023265321253 (前面是数字'0')
八进制更容易快速写下来,但十六进制具有很容易打破字节(这是十六进制数字对)的很好的属性。
一些帮助记住十六进制(通常称为“十六进制”)数字与十进制数字对应的对应关系:
- 十六进制0-9与十进制数字0-9相同
- A是过去9的第一个,很容易记住为10
- F是最后一个,因此容易记住为15
- C是十进制12(唯一一个你必须记住的)
- 所有其余的都接近A,C或F(B只是A + 1,D是C + 1,E是F-1)
如果有人提到一个数字的“第三位”,最好是从左边或右边找出它们是否意味着第三位,以及它们是否从0或1开始计数。错误传达可能导致真正的问题瘫痪(即,反转的字符串!)。 例如, 这个页面开始计数,最右边的位是数字1. 这个页面是一个宝石,答案5从右边开始计数,而答案8从右边开始计数从0开始。
几乎所有现代计算机都使用最左边的位作为“符号位”,如果其值为1,则表示负整数。注意,识别符号位的位置需要精确了解给定数据类型中的位数。此数字可能会随时间而变化(即,在其他计算机上重新编译时)。通常,sizeof()运算符将告诉您其参数包含的字节数 (通常为8位),例如,sizeof(int)或sizeof(100)将在32位计算机上产生4。有时,如果程序必须依赖于某个字(整数)长度,则可以识别包含正确常量的基于系统的包含文件。
在程序中使用二进制数
有时使用存储在数字中的位而不是仅仅将它们视为整数是很方便的。这种时间的例子包括记住选择(每个位槽可以是'是'/'否'指示符),跟踪选项标志(同样的想法,实际上,每个位槽是'是'/'否'指示器flag的存在),或跟踪多个小整数(例如,连续的位槽对可以记住0..3中的数字)。当然,偶尔编程任务实际上包含“位串”。
在C / C ++和其他语言中,如果您知道它的八进制或十六进制表示,则很容易分配二进制数:
i = 0x9AD5A2AB; / *十六进制:0x * /
要么
i = 023265321253; / * octal:以0 * /开头
更常见的是,组合一对单比特值的整数以创建感兴趣的整数。有人可能会认为下面的陈述会这样做:
i = 0x10000 + 0x100;
它会 - 直到符号位进入图像或相同的位被组合两次:
i = 0x100 + 0x100;
在这种情况下,发生'进位'(0x100 + 0x100 = 0x200,这可能不是您想要的结果),然后我可能需要包含0x200而不是0x100。'或'操作 - 表示为'|' 在C / C ++和其他方面 - 做对了。它使用以下四个规则组合了两个操作数中的相应位:
0 | 0 - > 0 0 | 1 - > 1 1 | 0 - > 1 1 | 1 - > 1'|' 操作在C中称为“按位或”,以免与它的堂兄'||'混淆 称为'逻辑或'或'orif'。'||' 运算符计算其左侧操作数的算术值,如果该值为假(正好为0),则计算其右侧操作数。'orif'运算符是不同的:如果任一操作数非零,则'||' 计算结果为true(C中恰好为1)。
“1 | 1 = 1”区分“|” 来自'+'的运算符。有时像这样的运算符会显示为“真值表”:
右操作数 运营商| | 0 1 --- + ------ 离开0 | 0 1 < - 结果 操作数1 | 1 1 < - 结果
很容易看出'按位或'运算是一种在整数内设置位的方法。输入位中的任何一个或两个都为'1'时产生'1'。
查询位的简单方法是使用'logical和'(也称为'bitwise和')运算符,该运算符表示为'&'并具有此真值表:
&| 0 1 --- + ------ 0 | 0 0 1 | 0 1不要将单个'&'运算符与名为'andif'的伙伴混淆为两个&符号('&&')。'andif'运算符将评估其左侧,如果左侧为假,则产生0,而不评估其右侧操作数。仅当左侧为真时才会评估右侧,并且运算符的结果是其真值的逻辑“和”(如上所述)并且被计算为整数0或整数1(vs. '&'在评估二进制100100和000111时会产生4)。
仅当*两个*输入位为'1'时才会产生'1'。因此,如果程序希望知道整数中0x100位是否为'1',则if语句很简单:
if(a&0x100){printf(“yes,0x100 is on n”); }
C / C ++(和其他)包含其他运算符,包括带有此真值表的'exclusive或'(表示为'^'):
^ | 0 1 --- + ------ 0 | 0 1 1 | 1 0
'exclusive or'运算符有时被称为'xor',以便于输入。Xor正好产生一个'1'或者它的输入中的一个*是一个:一个或另一个,但不是两者。此运算符非常便于“切换”(翻转)位,将它们从“1”更改为“0”,反之亦然。请考虑以下声明:
a = a ^ 0x100; / *与^ = 0x100相同; * /
0x100位将从0-> 1或1-> 0更改,具体取决于其当前值。
关闭一点需要两个操作员。新的是一元运算符,可以切换单词中的每一位,创建所谓的“按位补码”或只是单词的“补码”。有时这称为“位反转”或只是“反转”,并用波浪号表示:'〜'。这是一个简单的例子:
char a,b; / *八位,而不是32或64 * / a = 0x4A; / *二进制0100.1010 * / b = ~a; / *翻转每一位:1011.0101 * / printf(“b是0x%X n”,b);产量:
b是0xB5
因此,如果我们打开一个比特(例如,0x100),那么~0x100除了一个比特之外都有一个比特开启:0xFFFFFEFF(注意'E'作为右边的第三个'数字')(这个例子显示了一个32-位值; 64位值将在前面有更多的F)。
这两个运算符组合在一起创建了一个关闭位的方案:
a = a&(~0x100); / *关闭0x100位* / / *与&= ~0x100相同;由于~0x100中的所有位都打开,所以除了0x100位之外的所有位都出现在结果中。由于0x100位在~0x100中处于“关闭”状态,因此结果中该位保证为“0”。此操作通常称为“屏蔽”,如“屏蔽掉0x100位”。
概要
总之,这些运算符可以设置,清除,切换和测试整数中的任何位或位组合:
a | = 0x20; / *打开位0x20 * / a&= ~0x20; / *关闭位0x20 * / a ^ = 0x20; / *切换位0x20 * / if(a&0x20){ / *然后0x20位开启* / }
移
向左或向右移动位称为“移位”。考虑一下 五位二进制数,如00110.如果该数字被移位一个 向左,它变为:01100。另一方面,如果00110是移位 向右一位,它变为000011.数学上倾斜 用户会意识到向左移位一位是相同的 乘以2,同时向右移一位 与整数除以2相同(即,丢弃任何余数)。 通常为什么?一个接一个地移动-1会产生不寻常的结果(即,, 0xFFFF.FFFF >> 1 == 0xFFFF.FFFF,完全没有变化。
通常,人们可以指定多于一位的移位:移位 000001向左三位产生001000.移位运算符 是:
a << n / *左移n位 a >> n / *右移n位一般通常移位整数(而不是浮点数), 虽然没有什么能阻止某些人改变浮点数 语言。结果通常很难解释为a 浮点数,当然。
向左移动时,0'插入下端。向右移动时,高位是重复的并插入新需要的位(从而保留数字的符号)。这意味着(-1)>> 1产生-1而不是0!
另一种类型的转换,在大多数编程中原生不可用语言是'循环'移位,其中位移出一端插入在另一端而不是默认值0.现代此操作的使用很少见,但偶尔会出现。一些机器(例如,x86架构)具有汇编语言对此的说明,但谨慎的C或Java编程将花费更多的机器周期(十亿分之一秒)来执行移位然后是位提取移位或组合移动有点自己。
关于优化的说明:一些热心的优化编码器喜欢改变a / 4到'(a >> 2)'以节省时间(“因为乘法可以是现代编译器知道所有这些并执行此类操作自动替换,从而留下更好的程序员当这是什么意思时写一个/ 4。
非常先进的位操作
如果这是您第一次处理位,请跳过此部分。在你写完之后,将来在闲暇时阅读它操纵代码。真。
事实证明,2的补充机器代表整数的方式以及他们实施减法的方式(虚拟标准)所有现代机器)产生一些非常有趣的可能性位操纵。
二进制补码机器将正整数表示为二进制表示符号位为0的整数的表示。否定的整数表示为正整数的补码(包括打开符号位)加1.因此,绝对值最负的可表示整数比一个多最正的可表示整数。从而:
x + x,8位二进制-x,8位二进制 0 0000 0000 0000 0000 1 0000 0001 1111 1111 2 0000 0010 1111 1110 3 0000 0011 1111 1101 64 0100 0000 1100 0000 65 0100 0001 1011 1111 126 0111 1110 1000 0010 127 0111 1111 1000 0001 128 [无代表] 1000 0000
鉴于此表示,添加可以像铅笔一样进行和纸张,丢弃超过长度的任何超高位代表。从(ab)中减去b作为加法进行a和数量(-b)。
这意味着某些位操作可以利用这些定义证明,否定和减法产生有趣的结果其中留给读者(参见表格这些异地):
二进制 价值样本含义 x 00101100原始x值 x&-x 00000100提取最低位集 x | -x 11111100为其左侧的最低设置位和位创建掩码 x ^ -x 11111000创建最低位集左侧的掩码位 x&(x-1)00101000剥离最低位集 - >用于处理O中的单词(位集) 而不是O(一个字中的nbits) x | (x-1)00101111填写最低位设置以下的所有位 x ^(x-1)00000111为最低设置位和右侧的位创建掩码 ~x&(x-1)00000011为最低位集右侧的位创建掩码 x | (x + 1)00101101切换最低零位 x /(x&-x)00001011右移位数,因此最低设置位位于第0位没有理由记住这些表达,而是记住 有什么可以回顾这个页面以节省您的时间 处理位。
最后
以上就是漂亮小虾米为你收集整理的Binary Numbers的全部内容,希望文章能够帮你解决Binary Numbers所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复