深入理解计算机系统 第2章 习题解析 Part3
继续更新习题。
参考资料:
https://code.woboq.org/gcc/libiberty/calloc.c.html
https://dreamanddead.gitbooks.io/csapp-3e-solutions/content/
Chapter 2
72
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//有符号数和无符号数运算的结果为无符号数
void copy_int(int val, void *buf, int maxbytes){
if (maxbytes - sizeof(val) >= 0){
printf("copy_int copy successfully, size of val is %d, maxbytes is %d\n", sizeof(val), maxbytes);
memcpy(buf, (void *) &val, sizeof(val));
}
}
void copy_int_correct(int val, void *buf, int maxbytes){
int bytes = sizeof(val);
if (maxbytes - bytes >= 0){
printf("copy_int_correct copy successfully, size of val is %d, maxbytes is %d\n", sizeof(val), maxbytes);
memcpy(buf, (void *) &val, sizeof(val));
}
}
void test(){
void *buf = malloc(100);
int d = sizeof(int);
int maxbytes[2] = {d - 1, d};
int val = 0;
for (int i = 0; i < 2; i++){
copy_int(val, buf, maxbytes[i]);
copy_int_correct(val, buf, maxbytes[i]);
}
}
int main(){
test();
return 0;
}
73
#include <stdio.h>
int d;
long long TMin;
long long TMax;
/* Addition that saturates to TMin or TMax */
int saturating_add(int x, int y){
int z = x + y;
if (x >= 0 && y >= 0){
if (z < 0){
return TMax;
}else{
return z;
}
}else if (x < 0 && y < 0){
if (z >= 0){
return TMin;
}else{
return z;
}
}else{
return z;
}
}
int judge(int x, int y){
long long x1 = x;
long long y1 = y;
long long r1 = x1 + y1;
long long r2 = saturating_add(x1, y1);
if (r1 > TMax){
return r2 == TMax;
}else if (r1 < TMin){
return r2 == TMin;
}else{
return r1 == r2;
}
}
void test(){
long long data[5] = {TMin, -1, 0, 1, TMax};
int flag = 1;
for (int i = 0; i < 5; i++){
for (int j = 0; j < 5; j++){
int r = judge(data[i], data[j]);
if (!r){
long long r1 = data[i] + data[j];
long long r2 = saturating_add(data[i], data[j]);
printf("Wrong answer!\n");
printf("(%lld)+(%lld)=(%lld), answer of saturating_add is (%d)\n", data[i], data[j], r1, r2);
return;
}
}
}
printf("Pass test!\n");
}
int main(){
//初始化
d = sizeof(int) * 8;
TMin = 1 << (d - 1);
TMax = ~TMin;
//测试
test();
return 0;
}
74
#include <stdio.h>
#include <limits.h>
/* Determine whether arguments can be subtracted without overflow */
int tadd_ok(int x, int y){
int sum = x + y;
if (x >= 0 && y >= 0 && sum < 0){
return 0;
}else if (x < 0 && y < 0 && sum >= 0){
return 0;
}
return 1;
}
int tsub_ok(int x, int y){
//y=INT_MIN时-y=y
if (y == INT_MIN){
return x < 0;
}else{
return tadd_ok(x, -y);
}
}
void test(){
int num[5] = {INT_MIN, -1, 0, 1, INT_MAX};
for (int i = 0; i < 5; i++){
for (int j = 0; j < 5; j++){
int a = num[i];
int b = num[j];
long long c = (long long) a - (long long) b;
int d = a - b;
//判断结果
int f1 = (c == d);
int f2 = tsub_ok(a, b);
if (f1 != f2){
printf("Wrong answer for %d, %d!\n", a, b);
return;
}
}
}
printf("Pass test!\n");
}
int main(){
test();
return 0;
}
75
#include <stdio.h>
#include <limits.h>
int w = sizeof(int) * 8;
unsigned UNSIGNED_MAX = -1;
int signed_high_prod(int x, int y){
long long z = (long long) x * y;
z >>= w;
return z;
}
unsigned unsigned_high_prod(unsigned x, unsigned y){
int x1 = x;
int y1 = y;
//首位
int x0 = (x >> (w - 1)) & 1;
int y0 = (y >> (w - 1)) & 1;
//根据68页公式
unsigned z = signed_high_prod(x1, y1) + (x0 * y + y0 * x);
return z;
}
//实际结果
unsigned unsigned_high_prod_(unsigned x, unsigned y){
unsigned long long x1 = x;
unsigned long long y1 = y;
unsigned long long z = (x1 * y1) >> w;
return z;
}
void test(){
int n = 100;
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
unsigned long long x = UNSIGNED_MAX - i;
unsigned long long y = UNSIGNED_MAX - j;
unsigned long long z = x * y;
unsigned r1 = unsigned_high_prod(x, y);
unsigned r2 = unsigned_high_prod_(x, y);
//判断结果
if (r1 != r2){
printf("%x\n", r1);
printf("%x\n", r2);
printf("Wrong answer for %u, %u!\n", x, y);
return;
}
}
}
printf("Pass test!\n");
}
int main(){
test();
return 0;
}
76
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//参考https://code.woboq.org/gcc/libiberty/calloc.c.html
void *calloc(size_t nmemb, size_t size){
if (nmemb == 0 || size == 0){
return NULL;
}
size_t n = nmemb * size;
void * s = malloc(n);
if (s){
memset(s, 0, n);
}
return s;
}
int main(){
return 0;
}
77
#include <stdio.h>
int alu(int x, int k){
int res = 0;
if (k == 17){
//17=16+1
res = (x << 4) + x;
}else if (k == -7){
//-7=1-8
res = x - (x << 3);
}else if (k == 60){
//60=64-4
res = (x << 6) - (x << 2);
}else if (k == -112){
//-112=16-128
res = (k << 4) - (k << 7);
}
}
int main(){
return 0;
}
78
#include <stdio.h>
/* Divide by power of 2. Assume 0 <= k < w-1 */
int divide_power2(int x, int k){
if (x >= 0){
return x >> k;
}else{
return (x + (1 << k) - 1) >> k;
}
}
int main(){
return 0;
}
79
题意理解:
题目中说该函数会产生溢出,所以应该是先做乘法,再做除法,即$(3\times x )/4$,代码如下,其中mul3div4_是一开始写的版本,思路是带余除法:
不过求模运算应该替换掉比较好:
#include <stdio.h>
#include <limits.h>
/* Divide by power of 2. Assume 0 <= k < w-1 */
int divide_power2(int x, int k){
if (x >= 0){
return x >> k;
}else{
return (x + (1 << k) - 1) >> k;
}
}
int mul3div4_(int x){
int k = x / 4;
int r = x % 4;
int res = 3 * k + (3 * r) / 4;
return res;
}
int mul3div4(int x){
int res = divide_power2((x << 1) + x, 2);
return res;
}
void test(){
int num[5] = {-100, -1, 0, 1, 100};
for (int i = 0; i < 5; i++){
int x = num[i];
int r1 = mul3div4(x);
long long r2 = (long long) x * 3 / 4;
if (r1 != r2){
printf("%d %d\n", r1, r2);
printf("Wrong answer for %d!\n", x);
return;
}
}
printf("Pass test!\n");
}
int main(){
test();
return 0;
}
80
和上题不同的是,此题不会产生溢出,所以运算顺序是$(x/4)\times 3$,此题的思路如下,首先将$x$写成:
当$x\ge 0$时,$0\le r< 4$;当$x<0$时,$-4<r \le 0$;$k$可以通过divide_power2计算,从而计算出$r$,那么我们的结果为
所以代码如下:
#include <stdio.h>
#include <limits.h>
/* Divide by power of 2. Assume 0 <= k < w-1 */
int divide_power2(int x, int k){
if (x >= 0){
return x >> k;
}else{
return (x + (1 << k) - 1) >> k;
}
}
int mul3(int x){
return (x << 1) + x;
}
int threefourths(int x){
//向0舍入的除法
int k = divide_power2(x, 2);
//计算"余数", x < 0时"余数"为负
int r = x - (k << 2);
//向0舍入, 注意要考虑余数
int res = mul3(k) + divide_power2(mul3(r), 2);
return res;
}
void test(){
int num[7] = {INT_MIN, -99, -1, 0, 1, 99, INT_MAX};
for (int i = 0; i < 5; i++){
int x = num[i];
int r1 = threefourths(x);
long long r2 = (long long) x * 3 / 4;
if (r1 != r2){
printf("%d %d\n", r1, r2);
printf("Wrong answer for %d!\n", x);
return;
}
}
printf("Pass test!\n");
}
int main(){
test();
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
评论
ValineLivere