csapp reading notes 2 - representation and processing of information

information storage

Computers use binary numbers to store data, and when data is to be used, it is loaded into memory. The way the computer obtains these data is by addressing in memory, and the smallest unit of addressing is a byte (8 bits). The operating system abstracts the main memory and IO devices into a large array of bytes, called virtual memory , where each byte has a unique identifier, called an address , and the collection of these addresses is called the virtual address space .

hex

Computers use binary numbers to represent data, which is very verbose, but the book will use hexadecimal to represent data, which is more concise, the reason why decimal is not used is because binary conversion to decimal is more troublesome

Character

Word: The computer divides the data into words, and can only process one word of data at a time

Word length: The number of bits contained in each word, usually there are 32-bit word length machines and 64-bit word length machines

The virtual address is encoded in a word, and the computer operates on the data through the virtual address. The virtual space address range of word length w is 0 ~ 2^w -1. The upper limit of virtual space of 32-bit machine is 4GB, and the upper limit of virtual space of 64-bit machine is 16EB

32-bit programs and 64-bit programs represent whether the program is compiled in 32-bit or 64-bit, regardless of the number of bits of the machine (32-bit machines can be compiled with 64-bit, and 64-bit machines can be compiled with 32-bit). There are some data types in C language, and the number of bytes occupied by 32-bit programs and 64-bit programs is also different (for example, long occupies 4 bytes in 32-bit, and 8 bytes in 64-bit). Programmers should use exact types (int32_t and int64_t) to guarantee code portability

addressing and byte order

Usually multibyte objects are stored as a contiguous sequence of bytes

There are two ways to store object values: little endian and big endian. Mainstream machines are little endian

For example, the int type number a, its value is represented by hexadecimal as 0x01234567

Little-endian method: the high-order value of the value is first, and the low-order position is last; big-endian method: the low-order value of the value is first, and the high-order position is last

coding

Text files are portable across systems, while binary files are often not

Bit operations and logical operations

Bitwise operators: & (and), | (or), ^ (exclusive or), ~ (not)

Logical operators: && (and), || (or), ! (No)

All non-zero numbers in the logical operator task are TRUE, and 0 is FALSE, which are represented by 1 and 0 in the computer, and will return TRUE or FALSE after the calculation is completed.

Logical operators &&, || are calculated from left to right, and the result can be determined in advance according to an expression

shift

  • Left shift: <<, add 0 to the right
  • Logical right shift: >>, unsigned number in c language >> and >>> in java, fill 0 on the left
  • Arithmetic right shift: >>, signed number in c language >>, left complement sign bit

unsigned encoding

w-bit two unsigned can represent an integer between 0 ~ 2^w-1

two's complement encoding

The highest digit is "negative weight". When the highest digit is 1, it represents a negative number. The larger the number after removing the highest digit, the smaller the actual value. The smaller the number excluding the highest digit, the larger the actual value.

w-bit complement can represent integers between -2^(w-1) ~ 2^(w-1)-1

Convert between signed and unsigned

The complement code can be regarded as a signed number. The above figure shows the conversion diagram from signed to unsigned.

  • When the value is between 0 ~ 2^(w-1)-1, the mutual conversion value remains unchanged
  • When the number is in the range of -2^(w-1) ~ -1, the signed number is converted to an unsigned number in the range of -2^(w-1) ~ 2^w, and vice versa

Bit representation of an extended number (upcast)

Converting numbers from a smaller data type to a larger data type, such as byte to int, is from 8 bits to 32 bits, which can be automatically converted without loss of precision

In the program shown in the figure on a 32-bit machine, sx represents the short type, usx represents the unsigned short type, x represents the int type, and ux represents the unsigned int type. where x and ux are converted from sx and usx respectively

  • unsigned: extended by 0
  • Signed: Extend the sign bit

truncate numbers (downcast)

Converting numbers from a larger data type to a smaller data type, such as int to byte, may lose precision

truncate x to k-bit value x'

  • Unsigned: x' = x mod 2^k
  • Signed: y = x mod 2^k , convert y to k-bit signed value x', the highest bit k-1 bit sign bit

Suggestions for using signed and unsigned

When performing operations on signed numbers and unsigned numbers, the C language will convert signed numbers to unsigned numbers, which may cause changes in the converted values, resulting in bugs, so try to use unsigned values ​​when it comes to numerical operations. Unsigned values ​​are often useful if you just treat the bits in the number as a kind of flag or mask

unsigned addition

When x+y overflows, the highest bit is discarded, and the result is equal to the actual value of x+y minus 2^w

Detect overflow: overflow occurs when the result is less than x or y

signed addition

There are two actual overflow situations:

  • Positive overflow: Positive overflow results in the w-1 bit being 1. In order to facilitate the calculation, this number is extended by 1 bit to ensure that the value remains unchanged, that is, the w bit is 1, the remaining w-1 bit is the actual value of x+y, and the final result is x+y-2^w (actually and Not really extended by 1 bit, once the highest bit is extended it will be discarded)
  • Negative overflow: negative overflow will cause the w bit to be 1. If the w bit exceeds the upper limit of the signed type, it will be intercepted, which is equivalent to the actual value of x+y plus 2^w is the final result

Detect overflow: when x>0, y>0, if the result <=0, overflow; when x<0, y<0, if the result>=0, overflow

Unsigned, signed multiplication

Both need to truncate the result to k bits, but signed also needs to convert the resulting number to unsigned. The result of the multiplication can be saved to a 64-bit integer to prevent this overflow

### Multiply by a constant

Integer multiplication is slow on most machines, often taking more than 10 cycles, and other integer operations (addition, subtraction, bit operations) take only 1 cycle. Compilers tend to replace multiplication with a combination of shifts and additions and subtractions

For example 10=2^3+2^1, the compiler will optimize x*10 to(x<<3)+(x<<1)

Most compilers use this optimization when only a small number of shifts and additions and subtractions are needed

divide by a constant

Integer division is slower than multiplication on most machines, often taking more than 30 cycles. Moreover, the compiler can't optimize division by any constant. At present, it can only optimize the shift operation for division by the power of 2.

Integer division always rounds to 0, such as 3.14 -> 3,-3.14 -> -3,3 -> 3, the summary is that positive numbers are rounded down, and negative numbers are rounded up

Arithmetic right shifts unify to round down, causing negative right shifts and divisions to produce different results, eg -3/2=-1,而-3>>1=-2. So in practice, simple arithmetic right shift by N bits is not used to calculate the N power divided by 2

Discuss on y=x/(2^k)a case-by-case basis:

  • Divide an unsigned number by a power of 2: logically shift x to the right by k bits
  • Signed number divided by a power of 2: when x is less than 0, use (x+(1<<k)-1)>>k; otherwise, usex>>k

According to the above formula: a negative right shift may lose some bits, resulting in a smaller value, that is, rounding down. In order to make it round up, an offset needs to be added (1<<k)-1. For the case where no rounding is required, this The offset will eventually be shifted out. For the case where rounding is required, this offset will add 1 to the left bit of k bits, ensuring that the value is larger after shifting to the right by k bits, that is, rounding up.

floating point number

Now floating-point numbers are all IEEE standard floating-point format numbers, and the unified standard ensures the portability of floating-point numbers on different machines

binary decimal

Listed in the figure is a string of binary sequences, separated by decimal points, to simulate the representation of decimal floating-point numbers. This sequence is binary decimals.

The values ​​represented by this sequence are:

Binary decimals have the characteristics of binary numbers. The decimal point is shifted by N bits to the right to divide by 2^N, and shifted to the left by N bits to multiply by 2^N.

Binary decimals have limited ability to express numbers. Only by continuously increasing the length of binary numbers can the precision be improved and approach certain values.

IEEE floating point representation

Binary decimals will take up a lot of memory when representing large numbers, such as 5*(2^100). Using binary notation requires binary 101 followed by 100 0s.

Improvement: Using numbers x and y, x=5, y=100, the above large numbers can be expressed as x*(2^y)

IEEE floating point standard to V=(-1)^s * M * 2^Erepresent a number

  • Symbol s: Determines whether the number is positive (s=0) or negative (s=1), represented by one bit
  • Mantissa M: binary decimal, the range is between 1-2 or 0-1. Represented by the binary sequence frac
  • Exponent E: weights the floating point number, can be negative. Represented by the binary sequence exp

The c language divides the floating point number into three parts and encodes them separately

  • Single-precision float: 32 bits, 1 bit for s, 8 bits for E, 23 bits for M
  • Double precision double: 64 bits, 1 bit for s, 11 bits for E, 52 bits for M

Depending on the exponent, floating-point numbers are divided into four categories:

  • Normalization: Indicates a non-zero floating-point number, the value range of E is -126~+127, and the value range of M is 1~2
  • Denormalization: +0.0 when all are 0; s is 1, other 0 is -0.0; M is not all 0, it means a number very close to 0.0
  • Infinity: When E is all 1 and M is all 0, it means positive infinity or negative infinity according to whether s is 0 or 1
  • NAN: When E is all 1 and M is not all 0, it means an illegal number, that is, NAN

included

If the IEEE floating-point representation cannot accurately represent real numbers, rounding operation is required, and rounding is used by default.

Floating point, integer conversion

  • int to float, no overflow, possible rounding
  • Convert int or float to double, keep the exact value
  • double to float, possible overflow, possible rounding
  • float or double to int, rounding towards zero

Summarize

The advantage of 64-bit programs is that they can break through the 4GB address limit of 32-bit programs

Most machines use two's complement encoding for integers and IEEE standard encoding for real numbers

Unsigned to signed and signed to unsigned have risks leading to loss of precision and bugs

Restricted by the encoding length, real number operations may lead to loss of precision, numerical overflow, etc.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325445290&siteId=291194637