Applied

Representation of Numbers. Bitwise Operators

Course 07

Lect.eng. Adriana ALBU, PhD Politehnica University Timisoara Internal representation

• All data, of any type, processed by a computer must have the same fundamental representation • In order to work correctly with these data, a programmer should understand: – the representation of numbers and their memory storage – the fundamental manner a computer operates with numbers (bitwise operations) Representation of numbers

Binary Octal Hexadecimal Representation of numbers

• Most of our programs don’t need concern regarding operations at the bit level • We’re free to think in bytes, or integers and doubles, or even higher level data types composed of a combination of these • But there are times when we'd like to be able to go to the level of an individual bit Representation of numbers

• Any value (variable or constant) that is processed by our programs needs a memory space and it has a memory representation (sequence of bits) • Bit – unit of data storage – may have one of two values: 0 or 1 – usually is not individually addressable • Byte – unit of addressable data – in all usual computer architectures it contains 8 bits (CHAR_BIT from limits.h specifies its dimension) Representation of numbers

• The byte is the lowest level at which we can access data; there's no "bit" type, and we can't ask for an individual bit • In fact, we can't even perform operations on a single bit – every bitwise operator will be applied to, at a minimum, an entire byte at a time • This means we'll be considering the whole representation of a number whenever we talk about applying a bitwise operators Binary representation

• Binary numbers – used in mathematics and digital electronics – expressed in the binary numeral system (also called base-2 numeral system) – use two different symbols: 1 (one) and 0 (zero) – these two symbols may also have the meanings of true/false, yes/no, on/off • the binary system is used internally by almost all modern computers and computer-based devices such as mobile phones Binary representation

• Any number can be represented by a sequence of bits (binary digits), which in turn may be represented by any mechanism capable of being in two mutually exclusive states • In a computer, the numeric values may be represented by two different voltages Binary representation

• When written, binary numerals are often subscripted, prefixed or suffixed in order to indicate their base • The following notations are equivalent: – 11100101 binary (explicit statement of format) – 11100101b (a suffix indicating binary format) – 11100101B (a suffix indicating binary format) – bin 11100101 (a prefix indicating binary format)

– 111001012 (a subscript indicating base-2 (binary) notation) – %11100101 (a prefix indicating binary format) – 0b11100101 (a prefix indicating binary format, common in programming languages) – 8b11100101 (a prefix indicating number of bits in binary format, common in programming languages) Binary representation

• When spoken, binary numerals are usually read digit-by-digit, in order to distinguish them from decimal numerals – the binary numeral 100 is pronounced one zero zero, rather than one hundred, to make its binary nature explicit, and for purposes of correctness • since the binary numeral 100 represents the value four, it would be confusing to refer to the numeral as one hundred (a word that represents a completely different value, or amount) – alternatively, the binary numeral 100 can be read out as "four" (the correct value), but this does not make its binary nature explicit Counting in binary

• Counting in binary is similar to counting in any other number system • Beginning with a single digit, counting proceeds through each symbol, in increasing order • Before examining binary counting, it is useful to briefly discuss the more familiar decimal counting system as a frame of reference Decimal counting

• Decimal counting uses the ten symbols 0 through 9 • Counting primarily involves incremental manipulation of the "low-order" digit, or the rightmost digit, often called the "first digit” • When the available symbols for the low-order digit are exhausted, the next-higher-order digit (located one position to the left) is incremented, and counting in the low-order digit starts over at 0 Decimal counting

• In decimal, counting proceeds like so: – 000, 001, 002, ... 007, 008, 009, (rightmost digit starts over, and next digit is incremented) – 010, 011, 012, ... – ... – 090, 091, 092, ... 097, 098, 099, (rightmost two digits start over, and next digit is incremented) – 100, 101, 102, ... • After a digit reaches 9, an increment resets it to 0, but also causes an increment of the next digit to the left Binary counting

• In binary, counting follows similar procedure, except that only the two symbols 0 and 1 are used • Thus, after a digit reaches 1 in binary, an increment resets it to 0, but also causes an increment of the next digit to the left: – 0000, – 0001, (rightmost digit starts over, and next digit is incremented) – 0010, 0011, (rightmost two digits start over, and next digit is incremented) – 0100, 0101, 0110, 0111, (rightmost three digits start over, and the next digit is incremented) – 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111 ... Binary to decimal

• Since binary is a base-2 system, each digit represents an increasing power of 2, with the rightmost digit representing 20, the next representing 21, then 22, and so on • To determine the decimal representation of a simply take the sum of the products of the binary digits and the powers of 2 which they represent • For example, the binary number 100101 is converted to decimal form as follows: 5 4 3 2 1 0 – 1001012 = 1 × 2 + 0 × 2 + 0 × 2 + 1 × 2 + 0 × 2 + 1 × 2 – 1001012 = 1 × 32 + 0 × 16 + 0 × 8 + 1 × 4 + 0 × 2 + 1 × 1 – 1001012 = 3710 Decimal to binary

157 2 156 78 2 • Successive divisions by 2, 1 78 39 2 storing the reminder (0 or 1) 0 38 19 2 • Stop when the quotient is 0 1 18 9 2 1 8 4 2 • The binary result is the 1 4 2 2 sequence of reminders read 0 2 1 2 from the end to the beginning: 0 0 0 => 157 = 10011101 1 10 2 • Validation: 7 4 3 2 0 100111012 = 1 × 2 + 1 × 2 + 1 × 2 + 1 × 2 + 1 × 2 = 128 + 16 + 8 + 4 + 1 = 15710 Decimal to other bases

• This method can be modified to convert from decimal to any base • The divisor was 2 because the desired destination was base 2 (binary) • If the desired destination is a different base, replace the 2 in the method with the desired base • For example, if the desired destination is base 8, replace the 2 with 8 • The final result will then be in the desired base Decimal to octal

870 8 864 108 8 • Octal is base-8, with numbers 6 104 13 8 between 0 and 7 4 8 1 8 =>87010 = 15468 5 0 0 1 • common writing in programming languages: prefixed by zero: 01546 • Validation: 3 2 1 0 15468 = 1 × 8 + 5 × 8 + 4 × 8 + 6 × 8

= 512 + 320 + 32 + 6 = 87010 Decimal to hexadecimal

• The hexadecimal (base sixteen) numeral system has sixteen possible values, using the letters A, B, C, D, E, and F for the six place-values after 9:

Dec 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Hex 0 1 2 3 4 5 6 7 8 9 A B C D E F Oct 0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 Bin 0 1 10 11 100 101 110 111 1000 1001 1010 1011 1100 1101 1110 1111 Decimal to hexadecimal

19959 16 19952 1247 16 => 1995910 = 4DF716 7 1232 77 16 • common writing in 15 64 4 16 programming languages: (F) 13 0 0 prefixed by 0x: 0x4DF7 (D) 4

• Validation: 3 2 1 0 4DF716 = 4 × 16 + 13 × 16 + 15 × 16 + 7 × 16

= 16384 + 3328 + 240 + 7 = 1995910 Binary arithmetic

• Arithmetic in binary is much like arithmetic in other numeral systems – addition – subtraction – multiplication – division Addition

• The simplest arithmetic operation in binary is addition • Adding two single-digit binary numbers is relatively simple, using a form of carrying: – 0 + 0 → 0 Addition table – 0 + 1 → 1 0 1 – 1 + 0 → 1 0 0 1 1 0 1 1 10 – 1 + 1 → 0, carry 1 => 102 (1×2 +0×2 = 210) • Adding two "1" digits produces a digit "0", while 1 will have to be added to the next column Addition

• This is similar to what happens in decimal when certain single-digit numbers are added together; if the result equals or exceeds the value of the base (10), the digit to the left is incremented: – 5 + 5 → 0, carry 1 (since 5 + 5 = 10 = 1 × 101 + 0 × 100) – 7 + 9 → 6, carry 1 (since 7 + 9 = 16 = 1 × 101 + 6 × 100) • This is known as carrying • When the result of an addition exceeds the value of a digit, the procedure is to "carry" the excess amount divided by the radix (that is, 10/10) to the left, adding it to the next positional value Addition

• Carrying works the same way in 1 1 1 1 1 carried digits binary: 0 1 1 0 1 + – In this example, two numerals are being added together: 1 0 1 1 1 1 0 0 1 0 0 011012 (1310) and 101112 (2310) – The top row shows the carry bits used

– Starting in the rightmost column, 1 + 1 = 102; the 1 is carried to the left, and the 0 is written at the bottom of the rightmost column

– The second column from the right is added: 1 + 0 + 1 = 102 again; the 1 is carried, and 0 is written at the bottom

– The third column: 1 + 1 + 1 = 112; this time, a 1 is carried, and a 1 is written in the bottom row

– Proceeding like this gives the final answer 1001002 (3610) Subtraction

• Subtraction works in much the same way: starred columns are borrowed from – 0 − 0 → 0 * * * * – 0 − 1 → 1, borrow 1 1 1 0 1 1 1 0 − – 1 − 0 → 1 1 0 1 1 1 – 1 − 1 → 0 1 0 1 0 1 1 1 • Subtracting a "1" digit from a "0" digit produces the digit "1", while 1 will have to be subtracted from the next column • This is known as borrowing • The principle is the same as for carrying; when the result of a subtraction is less than 0, the least possible value of a digit, the procedure is to "borrow" the deficit divided by the radix from the left, subtracting it from the next positional value Multiplication

• Multiplication in binary is similar to its decimal counterpart • Two numbers A and B can be multiplied by partial products: for each digit in B, the product of that digit in A is calculated and written on a new line, shifted leftward so that its rightmost digit lines up with the digit in B that was used • The sum of all these partial products gives the final result Multiplication

• Since there are only two digits in binary, there are only two possible outcomes of each partial multiplication: – if the digit in B is 0, the partial product is also 0 – if the digit in B is 1, the partial product is equal to A

Multiplication table 0 1 0 0 0 1 0 1 Multiplication

• For example, the binary numbers 1110 and 1010 1 1 1 0 × are multiplied as follows: 1 0 1 0 11102=1410 0 0 0 0 + 1 1 1 0 + 10102=1010 10001100 =140 0 0 0 0 + 2 10 1 1 1 0 1 0 0 0 1 1 0 0 Division

• Binary division is again similar to its decimal counterpart:

• Here, the divisor is 1012, or 5 decimal, while the dividend is 110112, or 27 decimal • The procedure is:

– the divisor 1012 goes into the first three digits 1102 of the dividend one time, so a "1" is written on the result line – this result is multiplied by the divisor, and subtracted from the first three digits of the dividend; the next digit (a "1") is included to obtain a new three-digit sequence – the procedure is then repeated with the new sequence, continuing until the digits in the dividend have been exhausted Division

• Thus, the quotient of

110112 divided by 1012 is 1 1 0 1 1 1 0 1 1012, as shown on the 1 0 1 1 0 1 result line, while the 0 1 1 remainder, shown on the 0 0 0 bottom line, is 102 1 1 1 • In decimal, 27 divided by 1 0 1 5 is 5, with a remainder 1 0 of 2 The sizeof operator

Before operating with bits, an operator that determines the number of bytes used in a data type representation is needed The sizeof operator

• It is an unary operator used to determine the size of a data type, measured in number of bytes required to represent that type • It can be applied to any data type (standard or user- defined) The sizeof operator

• The keyword "sizeof" is followed by a type name or an expression (which may merely be a variable name) • If a type name is used, it must always be enclosed in parentheses, whereas expressions can be specified with or without parentheses – with data types, sizeof evaluates the size of the memory representation for an object of the specified data type – for expressions it evaluates the representation size for the type that would result from evaluation of the expression (which however is not evaluated) Why do we need sizeof?

• To write portable programs – sizes of types are implementation dependent (processor, operating system, compiler) – the dimension of a data type (even it is a standard data type) is not precisely defined by the standard (for instance, an integer can be represented on 2 or on 4 bytes); the only data type that has the same representation (using 1 byte) in any standard C implementation is char – for example, don’t write programs that assumes an integer has 2 bytes; it is possible to run incorrectly on other systems Why do we need sizeof?

• It is frequently very difficult to predict the sizes of compound data types such as a struct or a union • In bitwise operations and in dynamic memory allocation it is required to know how many bytes a variable or a data type has Example 1 – a C program

• since sizeof(char) is defined to be 1 and assuming that ints are 4 bytes long and doubles are 8 bytes long, the following code will print: 1, 8, 4:

#include void main(void){ int a; double b; char c; printf("%d, %d, %d", sizeof c, sizeof (a+b), sizeof(int)); } Bitwise operations

NOT, AND, OR, XOR, SHIFT Bitwise operations

• Though not directly related to the numerical interpretation of binary symbols, sequences of bits may be manipulated using Boolean logical operators • When a sequence of binary symbols is manipulated this way, it is called a – AND, OR, and XOR – may be performed on corresponding bits in two binary numerals provided as input – NOT operation – may be performed on individual bits in a single binary numeral provided as input – arithmetic shifts – other important operations (used, for instance, in multiplication or division by two) Bitwise operations in C

• Operations on bits at individual levels can be carried out using Bitwise operations in the C programming language • Bits come together to form a byte which is the lowest form of data that can be accessed in digital hardware • The whole representation of a number is considered while applying a bitwise operator Bitwise operators in C

• They can be used only for integer operands • C programming language provides six operators for bit manipulation:

Symbol Operator ~ bitwise NOT (unary operator) & bitwise AND | bitwise OR ^ bitwise eXclusive OR (XOR) >> right shift << left shift Bitwise NOT ~

• It represents the complement of a given number – for every bit 1, the result is 0 – for every bit 0, the result is 1

a ~ a 0 1 1 0

~10100011 = 01011100 Bitwise AND &

• It is just a representation of AND and does its work on bits and not on bytes, chars, integers, etc. • So basically a binary AND performs the logical AND on the bits in each position of a number in its binary form 11001110 & 10011000 a b a & b 10001000 0 0 0 • the most significant bit of the first number 0 1 0 is 1 and that of the second number is also 1, so the most significant bit of the result 1 0 0 must be 1 1 1 1 • in the second most significant bit, the bit of second number is zero, so the result is 0 Bitwise OR |

• Similar to Bitwise AND, Bitwise OR only operates on bits, not bytes • Its result is a 1 if one of the either bits is 1 and zero only when both bits are 0

11001110 | a b a | b 10011000 0 0 0 11011110 0 1 1 1 0 1 1 1 1 Bitwise XOR ^

• The Bitwise XOR (eXclusive OR) adds two bits while discarding the carry • The result is zero only when 2 zeroes or ones are involved

a b a ^ b • Sometimes XOR might just be used 0 0 0 to toggle the bits between 1 and 0 0 1 1 • Thus: i=i^1 when used in a loop 1 0 1 toggles its values between 1 and 0 1 1 0 Bitwise XOR ^

• You can think of XOR in the following way: – you have some bit, either 1 or 0, that we'll call A – when you take A XOR 0, then you always get A back: if A is 1, you get 1, and if A is 0, you get 0 – on the other hand, when you take A XOR 1, you flip A: if A is 0, you get 1; if A is 1, you get 0 • So you can think of the XOR operation as a sort of selective twiddle: if you apply XOR to two numbers, one of which is all 1s, you get the equivalent of a twiddle Right shift >>

• It requires two operands • It shifts each bit in its left operand to the right • The number following the operator (the right operand) decides the number of places the bits are shifted • Thus by doing ch>>3 all the bits will be shifted to the right by three places Right shift >>

• Example: – If the variable ch contains the bit pattern 11100101, then – ch >> 1 will give the output as 01110010, and – ch >> 2 will give 00111001 • If the number is unsigned, zeros are generated on the left when the bits are shifted to the right • Else – implementation dependent behavior (usually repeats the sign bit – the first bit of the number) => right shift only unsigned numbers (for portability) Right shift >>

• Right shift can be used to divide a bit pattern by 2 as shown: – i=14; // bit pattern 1110 – j=i>>1; /* the bit pattern is shifted by 1, obtaining 0111=7 which is 14/2 */ Example 2 – a C program

• A program that displays the binary representation of a number using the right shift operator

#include #include void main(void){ unsigned int n; int i; printf("n="); scanf("%u",&n); printf("%u = ", n); for(i=sizeof(unsigned int)*CHAR_BIT-1;i>=0;i--) printf("%u",(n>>i)&1); } Left shift <<

• It shifts each bit in its left operand to the left • It works opposite to that of right shift operator • Thus by doing ch<<1 on a variable ch that contains the bit pattern 01100101, the result will be 11001010 • Blank spaces generated are filled up by zeros Left shift <<

• Left shift can be used to multiply an integer by 2 as in: – int i=4; /* bit pattern is 100 */ – int j=i<<1; /* => 1000, which is 8 */ Example 3 – a C program

• A program that displays the binary representation of a number using the left shift operator

#include #include void main(void){ int i, n; printf("n="); scanf("%d",&n); printf("%d = ", n); for(i=sizeof(int)*CHAR_BIT-1;i>=0;i--) if((n&(1<

• C provides compound assignment operators – perform the binary operation – store the result in the left operand

Symbol Operator &= bitwise AND assignment |= bitwise OR assignment ^= bitwise XOR assignment >>= right shift assignment <<= left shift assignment The operators’ precedence

++, ––, (type), ~ *, /, % +, – <<, >> <, <=, >, >= ==, != & ^ | && || ?: =, +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>= Some applications of bitwise operators

• One and zero only for a specific bit k – 1<

• Get – a specific bit k of a number n (verify if it is 0 or 1): • n & (1<

01011110 & 0xF = 01011110 & 00001111 = 00001110 = 1410 Some applications of bitwise operators

• Set / Reset – set (to 1) a specific bit k of a number n: • n | (1< OR with 0 preserves a bit – reset (make 0) a specific bit k of a number n: • n & ~ (1< AND with 1 preserves a bit Some applications of bitwise operators

• Flip – XOR with 0 preserves a bit – XOR with 1 flips a bit – flip (change from 1 to 0 and from 0 to 1) a specific bit k of a number n: • n ^ (1<

• Example of other bit patterns (also called masks – the blue elements in the previous examples) – 11110000: ~ 0 << 4 – 00000011: ~ (~ 0 << 2) – 00111110: ~ (~ 0 << 5) << 1 – n & (~ (~ 0 << 2)) resets all bits of n, except last 2 bits – n & (~ (~ 0 << 5) << 1) resets all bits of n, except 5 bits starting from 1 Example 4 – a C program

• A program that works with a set of 8 LEDs (light- emitting diodes) stored as an unsigned char • It offers functions that: – verify if a given led is on or off; – turn on a specific led; – turn off a led; – flip a led. • All LEDs are initially turned off #include #include void display(unsigned char leds){ int i; for(i=CHAR_BIT-1;i>=0;i--) printf("%d",(leds>>i)&1); printf("\n"); } int isTurnedOn(unsigned char leds, int ledNumber){ return leds & (1<

• A program that adds two unsigned integers using AND, XOR and left shift

#include void main(void){ unsigned int x, y, carry; printf("x="); scanf("%u", &x); printf("y="); scanf("%u", &y); while(x!=0){ carry=x&y; y=x^y; carry=carry<<1; x=carry; } printf("sum=%u", y); } References

• Clint HICKS: “Utilizare C. Uşor şi repede”, Teora Printing House, 1996, ISBN 973-601-335-9 • Cprogramming – http://www.cprogramming.com • Wikipedia – http://en.wikipedia.org