
数据表示实验(计系实验二)
1.用二进制下科学计数法表示int型数时,尾数位数<=23,例如0x00008001,此时将0x8001左移24-16=8位得到frac,而exp则为127+16-1;如果是一个负数,则需要知道其最高的一位是0的。1.当x,y同号:此时,即可将问题转化为转换为p=y-x>=0,并对p的符号位(通过右移获得)进行判断,获得运行结果。对于前面的,当x不为0,即t=0时,需要 t转换为0xffff ff
实验目的与要求:
- 了解各种数据类型在计算机中的表示方法
- 掌握C语言数据类型的位级表示及操作
实验环境:
- 计算机(Intel CPU)
- Linux操作系统
实验步骤:
- 安装gcc-multilib:
输入sudo apt-get install gcc-multilib如fig1.
Fig1:安装gcc-multilib(1)
或者切换超级用户,再输入apt-get install gcc-multilib如fig2.
Fig1:安装gcc-multilib(2)
Fig2:f1安装好界面
安装编译环境:
gcc —v
Fig3:安装编译环境
2.根据bits.c中的要求补全以下的函数:
int bitXor(int x, int y);
int tmin(void);
int isTmax(int x);
int allOddBits(int x);
int negate(int x);
int isAsciiDigit(int x);
int conditional(int x, int y, int z);
int isLessOrEqual(int x, int y);
int logicalNeg(int x);
int howManyBits(int x);
unsigned float_twice(unsigned uf);
unsigned float_i2f(int x);
int float_f2i(unsigned uf);
首先把要做实验的东西放到一个文件夹中
Fig4:打开实验的文件夹
然后点击在终端打开
Fig5:在终端打开
输入 vi bits.c,补全其中的代码
Fig6:打开bits.c
补全后的代码如下图所示:
Fig7:修改前
Fig8:修改后
3.在Linux下测试以上函数是否正确,指令如下:
*编译:./dlc bits.c
*测试:make btest
./btest
实验过程及内容:(打开bits.c_中文说明.txt)
1. int bitXor(int x, int y); //异或操作
- 题目描述:
仅允许使用~和&来实现异或
例子: bitXor(4, 5) = 1
允许的操作符: ~ &
最多操作符数目: 14
- 思路:
列出两个输入时异或的真值表
x |
y |
output |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
0 |
Output=(∼x&y)∣(x&∼y)
又因为按位或不为合法运算符,只能使用~与&运算符。固由摩根定律可得:
Output = (∼x&y)∣(x&∼y)=∼(∼(∼x&y)&∼(x&∼y))
- 代码实现
Fig9:函数一代码
- 思路:
对于32位整数,最小值-231即为0X 8000 0000,即将1左移31位。
Fig10:函数二代码
3.int isTmax(int x);
- 题目描述:
如果x是最大的二进制补码,返回1;否则,返回0
允许的操作符: ! ~ & ^ | +
最多操作符数目: 10
- 思路:
法一:或者取反+1
法二:可以知道,最大值为0x7fff ffff,加一后将变为0x8000 0000,且此数加上本身后将变为0。本身加本身为0的数只有0和0x8000 0000,因此,只需将0xffffffff排除即可:
Fig11:函数三代码
- int allOddBits(int x);
- 题目描述
如果所有奇数位都为1则返回1;否则返回0
例子: allOddBits(0xFFFFFFFD) = 0,allOddBits(0xAAAAAAAA) = 1
允许的操作符: ! ~ & ^ | + << >>
最多操作符数目: 12
- 思路:
在二进制下,有且仅有所有位为奇数的数与0x5555 5555进行与运算后由0xffff ffff,变为0x0000 0000。因此可以通过对其与0x5555 5555进行与运算并取反再进行取逻辑反获得结果。又因为题干中不允许使用大于256的整数,故需要通过一些操作获得0x5555 5555。
可以通过将0x55分别进行左移8、16、24得到3个数,并将3个数求和获得0x5555 5555。
Fig12:函数四代码
- int negate(int x);
- 题目描述
返回x的相反数(-x)
例子: negate(1) = -1.
允许的操作符: ! ~ & ^ | + << >>
最多操作符数目: 5
- 思路:
即取反并加一返回即可。
Fig13:函数五代码
- int isAsciiDigit(int x);
- 题目描述
如果x是ascii码中的0~9,返回1;否则返回0
例子: isAsciiDigit(0x35) = 1.
isAsciiDigit(0x3a) = 0.
isAsciiDigit(0x05) = 0.
允许的操作符: ! ~ & ^ | + << >>
最多操作符数目: 15
- 思路:
即对于每个输入的x,需要满足x>=‘0’且x<=‘9’,因此可以将x与临界值进行作差。并通过右移31位判断对符号位进行判断是0还是1即可。
Fig14:函数六代码
7.int conditional(int x, int y, int z);
- 题目描述
实现x?y:z
例子: conditional(2,4,5) = 4
允许的操作符: ! ~ & ^ | + << >>
最多操作符数目: 16
- 思路:
对于x的判断可以通过t=!x进行判断实现,当x为0时返回1;当x不为0时返回0。因此,可以将表达式大致转成( _ &y)|( _ &z)的格式进行配凑。
对于前面的,当x不为0,即t=0时,需要 t转换为0xffff ffff(-1)。可以通过对1按位取反再加一1获得。
对于后面的,当x为0,即t=1时,也需要 t转换为0xffff ffff(-1)。此时直接对t进行取反并加一即可。
Fig15:函数七代码
8.int isLessOrEqual(int x, int y);
- 题目描述
如果x<=y返回1否则返回0
例子: isLessOrEqual(4,5) = 1.
允许的操作符: ! ~ & ^ | + << >>
最多操作符数目: 24
- 思路:
首先应该很容易会想到直接采用y-x并判断符号位的方法进行判断,但如果作差相减,有可能会发生int类型溢出,因此需要考虑其他方法。
1.当x,y同号:此时,即可将问题转化为转换为p=y-x>=0,并对p的符号位(通过右移获得)进行判断,获得运行结果。
2.当x,y异号:此时只要x>=0,就可以返回0,否则返回1。
3.是否同号的判断:可以通过对符号位进行求和判断是否同号。
Fig16:函数八代码
9. int logicalNeg(int x);
- 题目描述
实现!运算符的功能
例子: logicalNeg(3) = 0, logicalNeg(0) = 1
允许的操作符: ~ & ^ | + << >>
最多操作符数目: 12
- 思路:
利用其补码的性质,除了0和最小数外其他数,标志位都是互为相反数关系。
0和最小数的补码是本身,不过0的符号位与其补码符号位为0,最小数的为1,不影响。利用这一点得到解决方法。
Fig17:函数九代码
10. int howManyBits(int x);
- 题目描述
返回将X表示为补码所需的最小有效位数。
例子: howManyBits(12) = 5
howManyBits(298) = 10
howManyBits(-5) = 4
howManyBits(0) = 1
howManyBits(-1) = 1
howManyBits(0x80000000) = 32
允许的操作符: ! ~ & ^ | + << >>
最多操作符数目: 90
- 思路:
如果是一个正数,则需要找到它最高的一位(假设是n)是1的,再加上符号位,结果为n+1;如果是一个负数,则需要知道其最高的一位是0的。为了方便所以需要将负数取反。
接着从高16位开始检查是否存在1,如果存在则说明至少需要16位,截断x,并检查下一部分。
之后部分以此类推。
Fig18:函数十代码
11. unsigned float_twice(unsigned uf);
- 题目描述
以unsinged表示的浮点数二进制的二倍的二进制unsigned型
参数和结果都会被作为unsigned返回,但是会表示为二进制的单精度浮点值。
允许的操作符: 任何整数或者无符号数操作符包括: ||, &&. also if, while
最多操作符数目: 30
- 思路:
exp表示阶码位、frac表示尾数位)
通过分析可知,共存在三种可能的情况,分别考虑如下:
1.当exp=0xff时,直接返回本身即可;
2.当exp=0时,分两种情况考虑:
当uf[22]=0时,然后将frac左移一位即可
当uf[22]=1时,将exp自增1,然后再将frac左移一位即可
3.对于其他情况,将exp自增1,然后再分两种情况:
当exp==0xff,令frac=0即可。
其余情况正常左移并返回即可
Fig19:函数十一代码
12. unsigned float_i2f(int x);
- 题目描述
返回int x的unsigned浮点数的二进制形式
参数和结果都会被作为unsigned返回,但是会表示为二进制的单精度浮点值
允许的操作符: 任何整数或者无符号数操作符包括: ||, &&. also if, while
最多操作符数目: 30
- 思路:
(exp表示阶码位、frac表示尾数位)
首先,我们可以知道int型数据的表示范围为-231~231-1。
通过分析可知,主要有三种情况:
1.用二进制下科学计数法表示int型数时,尾数位数<=23,例如0x00008001,此时将0x8001左移24-16=8位得到frac,而exp则为127+16-1;
2.当尾数位数>23时,找到位数最末一位记作x[i],然后对尾数的舍去分3种情况考虑,并初始化c=0:
当x[i-1]=1且x[i-2]、x[i-3]…x[0]都为0,且x[i]=1,令c=1;
当x[i-1]=1且x[i-2]、x[i-3]…x[0]不都为0,令c=1;
其余情况 令c=0;
3.特殊情况:
对于x为0或为0x8000 0000的情况,在处理前进行特判即可。
Fig20:函数十二代码
13. int float_f2i(unsigned uf);
- 题目描述
返回unsigned uf的整型数的二进制形式
参数和结果都会被作为unsigned返回,但是会表示为二进制的单精度浮点值
任何超过范围的数都应该返回 0x80000000u.
允许的操作符: 任何整数或者无符号数操作符包括: ||, &&. also if, while
最多操作符数目: 30
- 思路:
为了方便进行计算,可以将uf(unsigned float)切割成符号位s,阶码exp和位数frac,分情况讨论:
1.当exp=0或exp-127<0时,返回0;
2.当exp-127>=31时候,超出表示范围,于是返回0x80000000u;
3.当exp-127<=23,根据符号位返回值num>>(23-(exp-127))
(exp表示阶码位、frac表示尾数位)
Fig21:函数十三代码
接着需要对上述修改完的函数是否正确进行测试。
先输入指令:
./dlc bits.c
进行编译
不会吐出任何东西
接着输入make,会有一些警告,但不会影响程序运行。
Fig22:测试
最后输入
./btest
运行程序
Fig23:测试结果图
可以判断,上述函数全部补充正确!
实验结论:
实验完成了!
心得体会:
Vi编辑器还是坏的,所以一开始输入vi bits.c
里面的代码全都是灰色的
这是一开始进去换行又出现了
需要进行以下操作:
- Vim编辑器的卸载
sudo apt-get remove vim-common (卸载Vim编辑器相关的软件包)
- 安装Vim
sudo apt-get install vim
完成后即可
还碰到了例如连不了网这种问题,详细叙述以及解决方法放在了实验三!
更多推荐
所有评论(0)