"In-depth understanding of computer systems" (CSAPP) experiment-Data Lab

This article is a supporting experiment in Chapter 2 of CSAPP. It uses limited operators to realize the bit-level representation of positive numbers, negative numbers, and floating-point numbers. By completing these 13 functions, we can better understand the encoding of data in the computer.

Ready to work

  First, go to the official website Lab Assignments to get the experiment-related files (you can also add my QQ to get teaching videos, PPT, etc.). The README of each experiment file details how to modify the program and compile the program. It is recommended to read it carefully and leave a message if you don't understand, and you will reply in time after you see it.

  My compilation environment: Ubuntu 16.04, gcc 5.4.0.

  The following error will be reported when compiling.

image-20201026150615228

  Execute the following command to install the 64-bit package.

sudo apt-get purge libc6-dev
sudo apt-get install libc6-dev
sudo apt-get install libc6-dev-i386

  Compile again, no error is reported, normal.

image-20201026150733398

topic

bitXor

Ideas

  De Morgan's law is also called inversion.

Code

/* 
 * bitXor - x^y using only ~ and & 
 *   Example: bitXor(4, 5) = 1
 *   Legal ops: ~ &
 *   Max ops: 14
 *   Rating: 1
 */
int bitXor(int x, int y) {
    
    
 return ~(x & y) & ~(~x & ~y);
}

tmin

Ideas

  The minimum value of the complement 0x80000000

Code

/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
    
    
  return 1<<31;
}

isTmax

Ideas

  Determine whether it is the maximum value of the complement. The maximum value of 32-bit complement is 0x7fffffff, which is XORed with it,

Code

/*
 * isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise 
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 2
 */
int isTmax(int x) {
    
    
  return !(x^0x7fffffff);
}

allOddBits

Ideas

  This problem is relatively simple, and it is solved by masking. First, we must construct the mask, use the shift operator to construct a mask with all 1s in odd digits, then get the odd digits of the input x value, clear the other bits (mask&x), and then perform an exclusive OR operation with the mask. If the same, the final result Is 0, and then returns the logical negation of its value.

Code

/* 方法一
 * allOddBits - return 1 if all odd-numbered bits in word set to 1
 *   Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 2
 */
int allOddBits(int x) {
    
    
  int mask = 0xAA+(0xAA<<8);
  mask=mask+(mask<<16);
  return !((mask&x)^mask);
}
/* 方法二
 * allOddBits - return 1 if all odd-numbered bits in word set to 1
 *   Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 2
 */
int allOddBits(int x) {
    
    
  return !(~x&0xaaaaaaaa);
}

negate

Ideas

  The complement is actually an abelian group, for x, -x is its complement, so -x can be obtained by adding 1 to x

Code

/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
    
    
  return ~x+1;
}

isAsciiDigit

Ideas

  The difference between x and '0' and '9' respectively, and then judge whether the sign bit is 0 or 1 according to the result of the difference

Code

/*

 * isAsciiDigit -return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')

 *   Example: isAsciiDigit(0x35) = 1.

 *            isAsciiDigit(0x3a) = 0.

 *            isAsciiDigit(0x05) = 0.

 *   Legal ops: ! ~ & ^ | + << >>

 *   Max ops: 15

 *   Rating: 3

 */

int isAsciiDigit(int x) {
    
    

  return(!((x+~48+1)>>31))&!!((x+~58+1)>>31);

}

conditional

Ideas

  Convert x to all 0s or all 1s. Note here that the complement of 0 is 0, and the bit represents all 0. The complement of 1 is -1, and the bit represents all 1. When x turns to all 0s and all 1, then (x&y) or (~x&z), one of them must be established. What is returned is the value of y or z

Code

/* 
 * conditional - same as x ? y : z 
 *   Example: conditional(3,4,5) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 16
 *   Rating: 3
 */
int conditional(int x, int y, int z) {
    
    
  x = !!x;
  x = ~x+1;//求补码
  return (x&y)|(~x&z);
}

isLessOrEqual

Ideas

  Comparing the size of two numbers by bit operation is nothing more than two cases: one is that the sign is different and the positive number is large, and the other is that the sign is the same to see the difference sign.

Code

/* 
 * isLessOrEqual - if x <= y  then return 1, else return 0 
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */
int isLessOrEqual(int x, int y) {
    
    
  int negX=~x+1;//-x
  int addX=negX+y;//y-x
  int checkSign = addX>>31&1; //y-x的符号
  int leftBit = 1<<31;//最大位为1的32位有符号数
  int xLeft = x&leftBit;//x的符号
  int yLeft = y&leftBit;//y的符号
  int bitXor = xLeft ^ yLeft;//x和y符号相同标志位,相同为0不同为1
  bitXor = (bitXor>>31)&1;//符号相同标志位格式化为0或1
  return ((!bitXor)&(!checkSign))|(bitXor&(xLeft>>31));//返回1有两种情况:符号相同标志位为0(相同)位与 y-x 的符号为0(y-x>=0)结果为1;符号相同标志位为1(不同)位与x的符号位为1(x<0)
}

logicalNeg

Ideas

  Logical negation means that non-zero is 1, and non-non-zero is zero. Utilizing the nature of its complement (inverted plus one), except for 0 and the smallest number ( sign bit is 1, the rest are 0 ), the other numbers are in opposite relationships (sign bit is either 1). The complement of 0 and the smallest number is itself, but the sign bit of 0 and its complement is either 0, and the smallest number is 1. Use this to get a solution.

Code

/* 
 * logicalNeg - implement the ! operator, using all of 
 *              the legal operators except !
 *   Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */

int logicalNeg(int x) {
    
    
  return ((x|(~x+1))>>31)+1;
}

howManyBits

Ideas

  The complement of a positive number: the highest 1 of a positive number is the nth number, plus the sign bit, the result is n+1.

  The complement of a negative number: Convert to a positive number, as above.

/* howManyBits - return the minimum number of bits required to represent x in
 *             two's complement
 *  Examples: howManyBits(12) = 5
 *            howManyBits(298) = 10
 *            howManyBits(-5) = 4
 *            howManyBits(0)  = 1
 *            howManyBits(-1) = 1
 *            howManyBits(0x80000000) = 32
 *  Legal ops: ! ~ & ^ | + << >>
 *  Max ops: 90
 *  Rating: 4
 */
int howManyBits(int x) {
    
    
  int b16,b8,b4,b2,b1,b0;
  int mask = x >> 31;
  x = (mask & ~x) | (~mask & x); //如果为正数,保持不变;如果为负数,按位取反

  //step1:判断高16为是否有1
  b16 = !!(x >> 16) << 4; //如果高16为有1,则b16 = 16,否则为0
  x >>= b16; //如果高16为有1,x右移16位舍弃低16位,在新的低16位继续查找;否则保持不变
  //step2:判断高8位是否有1
  b8 = !!(x >> 8) << 3;
  x >>= b8;
  //step3:高4位
  b4 = !!(x >> 4) << 2;
  x >>= b4;
  //step4:高2位
  b2 = !!(x >> 2) << 1;
  x >>= b2;
  //step5:高1位
  b1 = !!(x >> 1);
  x >>= b1;
  //step6:低1位
  b0 = x;

  return b16 + b8 + b4 + b2 + b1 + b0 + 1;
}

floatScale2

Ideas

Standard floating point format

Classification of single-precision floating-point values

  Refer to the figure above to understand. If you don’t understand, go back and look at the IEEE standard floating-point number format "In-depth understanding of computer systems" (CSAPP) reading notes-Chapter 2 Information Representation and Processing

  Mainly according to the input value, it can be divided into three situations:

  1. Enter uf as infinity and NaN, and return uf directly

  2. If uf is 0 or infinitesimal, return 2* uf + sign

  3. If exp+1 == 255, return infinity, otherwise return exp+1. (Exp is the integer part of the floating-point number encoding, exp+1 is equivalent to uf * 2.)

Code

/* 
 * floatScale2 - Return bit-level equivalent of expression 2*f for
 *   floating point argument f.
 *   Both the argument and result are passed as unsigned int's, but
 *   they are to be interpreted as the bit-level representation of
 *   single-precision floating point values.
 *   When argument is NaN, return argument
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned floatScale2(unsigned uf) {
    
    
  int exp = (uf&0x7f800000)>>23;//取出exp部分
  int sign = uf&(1<<31);//取出符号位
  if(exp==0) return uf<<1|sign;//情况2
  if(exp==255) return uf;//情况1
  exp++;
  if(exp==255) return 0x7f800000|sign;//情况3
  return (exp<<23)|(uf&0x807fffff);
}

floatFloat2Int

Ideas

image-20201027203703175

  1. Denormalization, which means that the number is very close to 0, which is 0 after being converted to an int value

  2. Normalization, the distribution of numbers is getting sparser from close to 0 to infinity. When f does not exceed the range of int type, it is converted to int; when it exceeds the range of int type, it returns 0x80000000u

  3. Special, return 0x8000000u

  When the normalized float is converted to an int integer,

  If E >= 31, the decimal point is shifted to the right by 31 bits. At this time, the implicit 1 and frac occupy 32 bits. In addition, a sign bit is required, which exceeds the range of int type

  If E <0, the decimal point is shifted to the left by 1 digit and then becomes 0.1frac, and after conversion to int, it becomes 0

  If 0 <E <23, after the decimal point is shifted to the left by E, some digits in frac need to be discarded. At this time, directly shift frac to the right by 23-E digits and erase the decimal part

  If 23 <= E <31, at this time, after the decimal point is shifted to the right, all frac is moved to the left of the decimal point, and frac is shifted to the left by E-23 digits, and zero is added at the end

Code

/* 
 * floatFloat2Int - Return bit-level equivalent of expression (int) f
 *   for floating point argument f.
 *   Argument is passed as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point value.
 *   Anything out of range (including NaN and infinity) should return
 *   0x80000000u.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
int floatFloat2Int(unsigned uf) {
    
    
  int sign = (uf >> 31) & 1;
  int exp = (uf >> 23) & 0xff;
  int frac = uf & 0x7fffff;

  int E = exp - 127;

  if (E < 0) //小数
  {
    
    
    return 0;
  }
  else if (E >= 31) // 超出int范围
  {
    
    
    return 0x80000000u;
  }
  else
  {
    
    
    frac = frac | (1 << 23);  //加上隐含的1

    if (E < 23)     //舍去部分小数
    {
    
    
      frac >>= (23 - E);
    }
    else        //不需要舍去小数
    {
    
    
      frac <<= (E - 23);
    }

    if (sign)
      return -frac;
    else
      return frac;
  }
}

floatPower2

Ideas

According to the floating-point number evaluation formula: V = (− 1) s × M × 2 EV = {(-1)^s} \times M \times {2^E}V=(1)s×M×2E

1. Standardization

令M=1(frac = 0),xEexp-Bias,exp=x+Bias

2. Denormalization

exp = 0, set a bit in frac to 1, thereby making x smaller.

exp frac M maxE MinE
Denormalization 0 0 * 10 * 0.frac -127 -148
Normalization Non-zero 0 1.0 127 -126

Analysis of boundary conditions

1. Denormalization

  • When frac = 100 0000 0000 0000 0000 0000, M = 0.1b = 0.5, E = 1- Bias = -126, at this time v = 0.5 * 2.0 ^ -126 = 2.0 ^ -127
  • When frac = 000 0000 0000 0000 0000 0001, M = 0.000 0000 0000 0000 0000 0001 = 2.0 ^ -22, E = -126, at this time v = 2.0 ^ -22 * 2 ^ -126 = 2.0 ^ -148

2. Standardization

  • When exp = 0xFF, E = exp-Bias = 127
  • When exp = 1, E = exp-Bias = -126

Code

unsigned floatPower2(int x) {
    
    
  if (x > 127) //too large, return +INF
  {
    
    
    return (0xFF << 23);
  }
  else if (x < -148) //too small, return 0
  {
    
    
    return 0;
  }
  else if (x >= -126) //norm,计算exp
  {
    
    
    int exp = x + 127;
    return (exp << 23);
  }
  else //denorm,令frac中某一位为1
  {
    
    
    int t = 148 + x;
    return (1 << t);
  }
}

Test Results

image-20201028110707561

to sum up

  The next few topics are still very brain-consuming, and I am at a loss when I get the topics. Later, I went to read the book again, understood the basic concepts, read the solutions of other people, and the problem was gradually clear. The code of the problem-solving process is also recorded, and there may be new solutions after returning to the second brush after a while. There are still a few experiments waiting for me later, take your time. Welcome to follow my blog for timely update notifications.

  Finally, I share a joke I saw on the PPT, counting sheep~ Haha~ Make it
QQ screenshot 20201028162245
  a habit, like it first, then watch it! If you think the writing is good, welcome to pay attention, like, bookmark, thank you!

Copyright statement: This article is the original article of the blogger and follows the CC 4.0 BY-SA copyright agreement. Please attach the original source link and this statement for reprinting.
Link to this article: https://blog.csdn.net/qq_16933601/article/details/109328995

Guess you like

Origin blog.csdn.net/qq_16933601/article/details/109328995