【CSAPP】家庭作业2.77~2.97

本文详细解答了计算机系统应用实践中的位级浮点编码问题,涵盖了一系列与整数乘法、除法、浮点计算、位模式表示、浮点数转换和位级浮点运算相关的算法和技巧。涉及的题目难度从星号到四星号不等,全面考察了对二进制和浮点数理解的深入程度。
摘要由CSDN通过智能技术生成

2.77**

:假设我们有一个任务:生成一段代码,将整数变量x乘以不同的常数因子K。为了提高效率,我们想只用+-<<运算。对于下列K的值,写出执行乘法运算的C表达式,每个表达式最多使用3个运算。

  1. K = 17
(x << 4) + x;
  1. K = -7
-(x << 3) + x;
  1. K = 60
(x << 6) - (x << 2);
  1. K = -112
-(x << 7) + (x << 4);

测试

#include <assert.h>

void csapp_2_77(int x)
{
   
	assert(((x << 4) + x) == x * 17);
	assert((-(x << 3) + x) == x * -7);
	assert(((x << 6) - (x << 2)) == x * 60);
	assert((-(x << 7) + (x << 4)) == x * -112);
}
int main()
{
   
	csapp_2_77(0);
	csapp_2_77(123);
	csapp_2_77(-123);
	printf("PASSED!\n");
	return 0;
}
[liheng@localhost2 2]$ ./a.out 
PASSED!

2.78**

:写出具有如下原型的函数的代码:

int divide_power2(int x, int k);

该函数要用正确的舍入方式计算 x / 2 k x/2^k x/2k

整数除法:向零取整。
右移除法:向下取整。
因此使用右移计算 x / 2 k x/2^k x/2k时要注意负数。如果x是负数就需要向上取整,要是它的低k位是非零的,就需要对右移结果+1

int divide_power2(int x, int k)
{
   
	int low_k = x & ~(~0 << k);
	int w = sizeof(int) << 3;
	int sign = (unsigned)x >> (w - 1);
	
	int res = x >> k;
	(sign && low_k && (res = res + 1));
	return res;
}

测试

int main()
{
   
	assert(divide_power2(1024, 4) == 1024 / 16);
	assert(divide_power2(-1024, 4) == -1024 / 16);
	assert(divide_power2(1027, 4) == 1025 / 16);
	assert(divide_power2(-1027, 4) == -1025 / 16);
	printf("PASSED!\n");

	return 0;
}
[liheng@localhost2 2]$ ./a.out 
PASSED!

2.79**

:写出函数mul3div4的代码,对于整数参数x,计算 3 ∗ x / 4 3*x/4 3x/4,注意 3 ∗ x 3*x 3x会产生溢出。

x分为两部分:

  1. 可以被4整除的部分
  2. 小于4的部分。

对于第一部分,先除以4再乘3;对第二部分,先乘3再除以4,如果x是负数,要注意向上取整。

#include <stdio.h>
#include <assert.h>
#include <stdint.h>
#include <limits.h>

int mul3div4(int x)
{
   
    int h = x & ~0x3;
    int hdiv4 = h >> 2;
    int hdiv4mul3 = (hdiv4 << 1) + hdiv4;

    int l = x & 0x3;
    int lmul3 = (l << 1) + l;
    int lmul3div4 = lmul3 >> 2;
    int sign = x >> ((sizeof(int) << 3) - 1);
    (sign && (lmul3 & 0x3) && (lmul3div4 = lmul3div4 + 1));

    return hdiv4mul3 + lmul3div4;
}

测试

int main()
{
   
    assert(mul3div4(0xffff) == (int64_t)0xffff * 3 / 4);
    assert(mul3div4(0xffffff) == (int64_t)0xffffff * 3 / 4);
    assert(mul3div4(INT_MAX) == (int64_t)INT_MAX * 3 / 4);
    assert(mul3div4(INT_MIN) == (int64_t)INT_MIN * 3 / 4);
    assert(mul3div4(-1) == (int64_t)-1 * 3 / 4);
    printf("PASSED!\n");
    return 0;
}
liheng@~/coding/csapp/2$ ./a.out 
PASSED!

2.80***

:写出函数threefourths的代码,对于整数参数x,计算 3 / 4 x 3/4x 3/4x的值,向零舍入,它不会溢出。
:同上。

2.81**

编写C表达式产生如下位模式,其中 α k \alpha^k αk表示符号 α \alpha α重复 k k k次。假设一个w位的数据类型,代码可以包含对参数jk的引用,它们分别表示jk的值,但是不能使用表示w的参数。

  1. 1 w − k 0 k 1^{w-k}0^k 1wk0k
~0 << k;
  1. 0 w − k − j 1 k 0 j 0^{w-k-j}1^{k}0^j 0wkj1k0j
(1 << (j + k)) - (1 << j);

2.82*

:我们在一个int类型值为32位的机器上运行程序。这些值以补码形式表示,而且它们都是算术右移的,unsigned类型的值也是32位的。
我们产生随机数xy,并且把他们转换成无符号数,显示如下:

int x = random();
int y = random();
unsigned ux = (unsigned)x;
unsigned uy = (unsigned)y;

对于下列每个C表达式,你要指出表达式是否总是为1,如果是,请描述其中的原理;如果不是,列举出使它为0的例子。

  1. (x < y) == (-x > -y)
    否。当x = INT_MIN, y = -1时,-x还是INT_MIN-y = 1,明显-x < -y
  2. ((x + y) << 4) + y - x == 17 * y + 15 * x
    是。左移4位相当于乘16,乘法满足分配律。
  3. ~x + ~y + 1 == ~(x + y)
    是。根据补码运算规则-x = ~x + 1, -y = ~y + 1得到~x = -x - 1, ~y = -y - 1,得到:
    -x - 1 + (-y) - 1 + 1 = -x - y - 1 = -(x + y) - 1 = ~(x + y)
  4. (ux - uy) == -(unsigned)(y - x)
    是。无符号数和补码数有同样的位级行为。
  5. ((x >> 2) << 2) <= x
    是。x的低2位可能会变小,低2位是正权,所以整体值可能会减小。

2.83**

:一些数字的二进制表示是由形如0.yyy...的无穷串组成的,其中y是一个k位的序列。例如, 1 3 \frac{1}{3} 31的二进制表示是0.01010101...(y=01),而 1 5 \frac{1}{5} 51的二进制表示是0.001100110011...(y=0011)

  1. Y = B 2 U k ( y ) Y=B2U_k(y) Y=B2Uk(y),也就是说,这个数具有二进制表示y。给出一个由Yk组成的公式表示这个无穷串的值。
    定义n = 0.yyy...,则(n << k) = y.yyy...(n << k) - n = Y,因此 n ∗ ( 2 k − 1 ) = Y n*(2^k-1)=Y n(2k1)=Y,即 n = Y 2 k − 1 n=\frac{Y}{2^k-1} n=2k1Y
  2. 对于下列的y值,串的数值是多少?
  • 101
    n = 5 2 3 − 1 = 5 7 n=\frac{5}{2^3-1}=\frac{5}{7} n=2
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值