Computer system experiment 1: data experiment datalab

Problem Description

Your goal is to modify your copy of bits.c so that it passes all tests in btest without violating any coding guidelines.

lab environment

ubuntu 16.04

Experimental content

1. Function bitand
The function of this function is to realize the phase-wise AND of two numbers. Since only | and ~ can be used, the expression is transformed considering De Morgan's law.

int bitAnd(int x, int y) {
    
    
	return ~((~x)|(~y));
}

2. Function getByte
The function of this function is to get the nth byte from the parameter x. The idea is: shift the parameter x to the right by n bytes. At this time, the byte to be fetched is on the far right. The number and 0xff can be phased.

int getByte(int x, int n) {
    
    
	n=n<<3;
	x=x>>n;
	return x&0xff;
	
}

3. Function logicalShift
The function of this function is to logically shift the parameter x to the right by n bits. Note that the difference between the logical right shift and the arithmetic right shift here is that the high bit of the logical right shift is filled with 0, so for the parameter x that may be negative, you need Consider changing its high bit to 0. The idea is to shift its parameter x to the right by n bits, and then AND with 0000...11111 (n 0s), then the high bit can be changed to 0.

int logicalShift(int x, int n) {
    
    
  	return ~(((1<<31)>>n)<<1)&(x>>n);
}

4. Function bitAnd
The function of this function is to return the number of 1s in the binary representation of the number. The idea is to use the dichotomy method to first obtain mask1 corresponding to 32-bit 0101010101..., mask2 corresponding to 32-bit 00110011..., mask3 corresponding to 32-bit 00001111 ..., mask4 corresponds to 32-bit 0000000011111111..., and mask5 corresponds to 32-bit low bits are all 1. First calculate the number of 1s in every two digits in x, use num to record the number of 1s, and so on, calculate the number of 1s in every 4 digits, 8 digits, and 16 digits, and finally the integrated result is 1 in x the number of . Each misplacement is equivalent to an addition.

int bitCount(int x) {
    
    
	int num=0;
	int tmpmask1=(0x55)|(0x55<<8);
	int mask1=(tmpmask1)|(tmpmask1<<16);
	int tmpmask2=(0x33)|(0x33<<8);
	int mask2=(tmpmask2)|(tmpmask2<<16);
	int tmpmask3=(0x0f)|(0x0f<<8);
	int mask3=(tmpmask3)|(tmpmask3<<16);
	int mask4=(0xff)|(0xff<<16);
	int mask5=(0xff)|(0xff<<8);
	num=(x&mask1)+((x>>1)&mask1);
	num=(num&mask2)+((num>>2)&mask2);
	num=(num+(num>>4))&mask3;
	num=(num+(num>>8))&mask4;
	num=(num+(num>>16))&mask5;
	return num;
}

5. Function bang
The function of this function is to realize the logical inversion operation. For the inversion of non-zero numbers, the output is 0, and the output of zero inversion is 1. The idea is to first OR the number with its opposite number. If the parameter is zero, the result obtained here It is all 0. If the parameter is a non-zero number, there are only two results, either all 1 or 0x80000000. Then shift the obtained number to the right by 31 bits and invert it bit by bit. For 0, the result is all 0, and for non-zero numbers, the result is all 1, and finally return the result of ANDing with 1.

int bang(int x) {
    
    
	int temp=x|(~x+1);
	temp=~(temp>>31);
	return (temp&1);
}

6. Function tmin
The function of this function is to return the smallest 32-bit two’s complement integer, that is, 0x80000000, just shift 1 to the left by 31 bits.

int tmin(void) {
    
    
  return (1<<31);
}

7. Function fitBits
The function of this function is to judge whether the parameter x can be represented by n-bit two’s complement, which is equivalent to judging whether x is between -2 (n-1) and 2 (n-1)-1. Consider dividing it into two cases. If it is within the range, after moving it to the right by n-1 bits, the result obtained by adding 1 and then shifting should be 0, and if it is not within the range, then the result obtained by the above operation It should be 1, and then just invert the result.

int fitsBits(int x, int n) {
    
    
 	return !(((x>>(n+(~0)))+1)>>1);
}

8. Function divpwr2
The function of this function is to calculate x/(2 n), the idea is to discuss x in different situations, when x is a positive number, you can directly shift n bits to get x/(2 n), but for negative numbers The situation is different. The shift operation of a negative number is to round to the negative, but in this question it is necessary to round to 0, so consider adding an offset to the negative number so that it can be directly shifted to get the target after adding the offset. value.

int divpwr2(int x, int n) {
    
    
	int sign=x>>31;
	int mask=(1<<n)+(~0);
	return (x+(sign&mask))>>n;
}

9. Function negate
The function of this function is to return the opposite number. According to the calculation method of the opposite number in complement code, just add one after bitwise inversion.

int negate(int x) {
    
    
	return ((~x)+1);
}

10. Function ispositive
The function of this function is to judge whether x is positive. The idea is to divide the number into two cases, one is 0, and the other is not 0. When it is not 0, shift the number to the right by 31 bits. If it is a positive number, it will get all 0s, and if it is a negative number, it will get all 1s; when it is 0, the function returns 0.

int isPositive(int x) {
    
    
	return !((x>>31)|(!x));
}

11. Function isLessOrPositive
The function of this function is to judge whether x<=y is true. The value of xy cannot only be judged here, because there may be overflow, so it needs to be discussed on a case-by-case basis. The first is the case where the two numbers have different signs. In this case, we can use the expression (!signy)&signx to express the result; the second is the result of the two numbers having the same sign. At this time, we judge the sign of the subtraction result of the two numbers. But, in the end, it is the case where the two numbers are equal. In this case, you only need to look at the two numbers or the result. Combining the above three situations or can meet the requirements.

int isLessOrEqual(int x, int y) {
    
    
	int signx=(x>>31)&1;
	int signy=(y>>31)&1;
	int sign=(!signy)&signx;
	int tmp=x+((~y)+1);
	tmp=((tmp>>31)&1)&(!(signx^signy));
	return (sign|tmp|((!(x^y))));
}

12. Function ilog2
The function of this function is to take the logarithm of x. The idea is also to use the divide and conquer method. First, the 32-bit length is processed into a 16-bit length. (!!(x>>16))<<4 realizes that when x is greater than 2^16, first record 16 (1<< 4), otherwise this step is 0, then bitsNumber+((!!(x>>(bitsNumber+8)))<<3), when x is greater than 16, the recorded bitsNumber is also added to the removed 16+8 digits after digits, so that the first half of the 16-bits are processed, and the cycle continues in turn. Otherwise, when the bitsNumber is less than 16, the last 8 bits of the last 16-bits are processed, and so on, to get the final result.

int ilog2(int x) {
    
    
	int bitsnumber=0;
	bitsnumber=(!!(x>>16))<<4;
	bitsnumber=bitsnumber+((!!(x>>(bitsnumber+8)))<<3);
	bitsnumber=bitsnumber+((!!(x>>(bitsnumber+4)))<<2);
	bitsnumber=bitsnumber+((!!(x>>(bitsnumber+2)))<<1);
	bitsnumber=bitsnumber+(!!(x>>(bitsnumber+1)));
	return bitsnumber;
}

13. Function float_neg
The function of this function is to return the opposite of the floating-point number. Pay attention to the case where the result is NaN. It is stated in the title that if the result is NaN, return the original value. `

unsigned float_neg(unsigned uf) {
    
    
	unsigned t=uf&0x7fffffff;
	if(t>0x7f800000)
	return uf;
	return uf^(1<<31);
}

14. Function float_i2f
The function of this function is to return the binary form of the floating-point number of the integer variable x, and return the binary form of the floating-point number of the integer variable x. When x=0, return 0, when x is less than 0, take sign as 1000..., and absX as its absolute value. The absolute value is continuously shifted to the left, shiftLeft records the number of left shifts until the highest bit is 1, and afterShift is the result of the left shift. 0x01ff is 111111111, 0x0100 is 100000000, judge whether carry is needed, if necessary, flag is 1. Floating-point numbers can be divided into three parts, sign bit, exponent code, and mantissa. Just add unsigned integers.

unsigned float_i2f(int x) {
    
    
	unsigned shiftleft=0;
	unsigned aftershift, tmp, flag;
	unsigned absx=x;
	unsigned sign=0;
	if(x==0)
	return 0;
	if(x<0){
    
    
	sign=0x80000000;
	absx=-x;
	}
	aftershift=absx;
	while(1)
	{
    
    
	tmp=aftershift;
	aftershift=aftershift<<1;
	shiftleft++;
	if(tmp&0x80000000)
	break;
	}
	if((aftershift&0x01ff)>0x0100)
	flag=1;
	else if((aftershift&0x03ff)==0x0300)
	flag=1;
	else flag=0;
	return (sign+(aftershift>>9)+((159-shiftleft)<<23)+flag);
}

15. Function float_twice
The function of this function is to return the result of multiplying the floating-point number by 2. If the exponent code is all 0, then consider the sign bit and shift it to the right. If the order code is not all 1, add 1 to the order code, and return directly without processing other cases.

unsigned float_twice(unsigned uf) {
    
    
	unsigned f=uf;
	if((f&0x7f800000)==0){
    
    
	f=((f&0x007fffff)<<1)|(0x80000000&f);
	}
	else if((f&0x7f800000)!=0x7f800000){
    
    
	f=f+0x00800000;
	}
	return f;
}

Guess you like

Origin blog.csdn.net/weixin_51295681/article/details/124236312