The Hardware / Software Interface Lab1

华盛顿大学的 CSE 351 课程 The Hardware / Software Interface https://courses.cs.washington.edu/courses/cse351/17wi/schedule.html ,该课程原来有一个 Coursera 版本,后来 Coursera 平台大升级,导致这门课在 Coursera 看不了。不过还是可以华盛顿大学的网站上找得到对应的课程视频,地址在这里 https://courses.cs.washington.edu/courses/cse351/17wi/videos.html
该课程的动手操作实验移植于计算机经典书籍《深入理解计算机系统》的实验。这篇文章是第一个实验 Lab1 的解答。

规则限制

简单介绍一下代码实现的规则

  1. 不允许使用 if,else,以及其他条件语句
  2. 不能使用宏定义
  3. 不能添加额外的函数
  4. 不能调用其他函数
  5. 能使用的操作符会在每题题目中说明,除此之外其他的都不能使用
  6. 不能使用数据类型转换
  7. 不能使用 int 之外的其他数据类型
  8. 使用课程实验提供的虚拟机

注意:文章中提到的 “位置” 都是从 int 的二进制角度来描述的,位置是 int 的二进制表示中某个 bit 的所在排列位置。

第一题

题目:

/* 
 * bitAnd - x&y using only ~ and | 
 *   Example: bitAnd(6, 5) = 4
 *   Legal ops: ~ |Xor
 *   Max ops: 8
 *   Rating: 1
 */
int bitAnd(int x, int y) {
  return 2;
}

解题思路:

  1. x & y 的操作结果是,x 和 y 中所有对应位置的 bit 同时为 1 的时候结果为 1,否则结果为 0
  2. 使用 ~(x) | (~y) 操作将 x 和 y 中同时为 1 的 bit 的值置为 0,其他 bit 位置的值置为 1
  3. 执行 ((x)|(~y)) ,在 2 的结果上取反,得到解题结果

解题方案:

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

第二题

题目:

/*
 * 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 2;
}

解题思路:

  1. (x&y) 操作将 x 和 y 中 对应位置的 bit 值同时为 1 的 位置置
    1 保留下来,其余位置置 0
  2. (x)&(y) 操作将 x 和 y 中 对应位置的 bit 值中同时为 0 的位置置 1 保留下来,其余位置置0
  3. (~(x&y)) 把 1 步骤的结果做 ~ 操作,将 x 和 y 中 对应位置的 bit 值中同时为 1 的位置置0,其余位置置1,保留下来
  4. (((x)&(~y))) 把 2 步骤的结果做 ~ 操作,将 x 和 y 中 对应位置的 bit 值中同时为 0 的位置置 0 ,其余位置置 1,保留下来
  5. ((x&y))&(((x)&(y))) 将 3 步骤和 4 步骤的结果做 & 操作,将 x 和 y 中对应位置同时为 0 和同时为 1 的位置置为 0 ,其他位置置为 1,得到解题结果

解题方案:

int bitXor(int x, int y) {
  return (~(x&y))&(~((~x)&(~y)));
}

第三题

题目:

/* 
 * thirdBits - return word with every third bit (starting from the LSB) set to 1
 * and the rest set to 0
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 8
 *   Rating: 1
 */
int thirdBits(void) {
    return 2;
}

解题思路:
题目是要让我们构造一个这样的数据 0100 1001 0010 0100 1001 0010 0100 1001 。

  1. 我们设定一个初始数据 0100 1001,转成 16 进制表示 int x = 0x49
  2. 在 1 步骤上做 x << 9 操作得到数据 1001 0010 0000 0000,int y = x << 9
  3. 在 1 步骤和 2 步骤的基础上执行 (x + y) << 18 操作得到数据 0100 1001 0010 0100
  4. 在 3 步骤的基础上执行 ((x + y) << 18) + (x + y) 操作得到数据 0100 1001 0010 0100 1001 0010 0100 1001,得到解题结果

解题方案:

int thirdBits(void) {
    int x = 0x49;
    int y = x << 9;
    return ((x + y) << 18) + (x + y);
}

第四题

题目:

/* 
 * fitsBits - return 1 if x can be represented as an 
 *  n-bit, two's complement integer.
 *   1 <= n <= 32
 *   Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 2
 */
int fitsBits(int x, int n) {
  return 2;
}

解题思路:
这个题目是要判断一个数字能否被 n 个 bit 位表示

  1. 假定一个数字可以被 n 个 bit 位表示,那么也可以认为左边的 (32-n) 位是没用的位置,所以做 ((x << (32 - n)) 操作
  2. 在 1 步骤的基础上做 ((x << (32 - n)) >> (32 - n)) 操作,假定一个数字可以被 n 个 bit 位表示,那么在经过这个操作之后,这个数字还是不变的
  3. 在 2 步骤的基础上做 !(((x << (32 - n)) >> (32 - n)) ^ x ) 操作,判断 ((x << (32 - n)) >> (32 - n)) 和 x 是否是同一个数字,得到解题结果

解题方案:

int fitsBits(int x, int n) {
  return (!(((x << (32 - n)) >> (32 - n)) ^ x ));
}

第五题

题目:

/* 
 * sign - return 1 if positive, 0 if zero, and -1 if negative
 *  Examples: sign(130) = 1
 *            sign(-23) = -1
 *  Legal ops: ! ~ & ^ | + << >>
 *  Max ops: 10
 *  Rating: 2
 */
int sign(int x) {
  return 2;
}

解题思路:

  1. 取出 x 的符号位 (x >> 31) x为负数结果为 0x11111111 x为正数结果为 0x00000000 x为零结果为 0x00000000
  2. 取出 -x 的符号位 ((~x +1) >> 31) x为负数结果为 0x00000000 x为正数结果为 0x11111111 x为零结果为 0x00000000
  3. 在 2 步骤 的基础上进行 & 0x01 操作 (((~x +1) >> 31) & 0x01)) ,取出最后一位 x为负数结果为 0 x为正数结果为 1 x为零结果为 0
  4. 在 1步骤 和 3步骤 的基础上做 | 操作,x为负数结果为 0x11111111 ,x为正数结果为 0x00000001 , x为零结果为 0x00000000,得到解题结果

解题方案:

int sign(int x) {
  return ((x >> 31) | (((~x +1) >> 31) & 0x01));
}

第六题

题目:

/* 
 * getByte - Extract byte n from word x
 *   Bytes numbered from 0 (LSB) to 3 (MSB)
 *   Examples: getByte(0x12345678,1) = 0x56
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 6
 *   Rating: 2
 */
int getByte(int x, int n) {
  return 2;
}

解题思路:
1.一个 byte 等于 8(2的3次方) 个 bit,将 n 乘以 8 也就是 n = n << 3 得到想要取出的 byte 在 x 的二进制表示的开始位置

  1. x = x >> n,将想要取出的 byte 移动到最低 8 位
  2. (x & 0xff),将 x 与 0xff 进行 & 操作,取出最低 8 位,得到解题结果

解题方案:

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

第七题

题目:

/* 
 * logicalShift - shift x to the right by n, using a logical shift
 *   Can assume that 0 <= n <= 31
 *   Examples: logicalShift(0x87654321,4) = 0x08765432
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 3 
 */
int logicalShift(int x, int n) {
    return 2;
}

解题思路:

  1. 实现逻辑左移操作,需要一个 mask ,该 mask 可以将左到右的 n 个位置清零
  2. (0x1 << 31) 的操作结果为 0x10000000
  3. (0x1 << 31) >> n 将 2 步骤的结果右移 n 位 实现从左边到右边的 n+1 位为 1,其余位置为 0 的效果
  4. ((0x1 << 31) >> n << 1) 将 3 步骤的结果左移 1 位,实现从左边到右边的 n 位为 1,其余位置为 0 的效果
  5. (~((0x1 << 31) >> n << 1)) 的操作,实现从左边到右边的 n 位为 0,其余位置为 1 的效果
  6. (x >> n) & (~((0x1 << 31) >> n << 1)) 实现逻辑左移的效果,得到解题答案

解题方案:

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

第八题

题目:

 * addOK - Determine if can compute x+y without overflow
 *   Example: addOK(0x80000000,0x80000000) = 0,
 *            addOK(0x80000000,0x70000000) = 1, 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 3
 */
int addOK(int x, int y) {
    return 2;
}

解题思路:

  1. overflow 是指数据的表示超出了整数的表示范围,两个正整数或者两个负整数相加就有可能超过这个整型变量所能表示的范围,有可能产生 overflow
  2. x > 0, y > 0, (x + y) < 0 ,x < 0, y < 0, (x + y) > 0 这 2 种情况都是 overflow
  3. int a = x >> 31,取出 x 的符号位
  4. int b = y >> 31, 取出 y 的符号位
  5. int c = (x + y) >> 31,取出 x + y 的符号位
  6. !((~(a ^ b)) && (a ^ c)),判断 x,y,x+y 符号是否一致,得到解题答案

解题方案:

int addOK(int x, int y) {
    int a = x >> 31;
    int b = y >> 31;
    int c = (x + y) >> 31;
    return !((~(a ^ b)) && (a ^ c));
}

第九题

题目:

/* 
 * bang - Compute !x without using !
 *   Examples: bang(3) = 0, bang(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */
int bang(int x) {
    return 2;
}

解题思路:

  1. 在 c 语言中, 0 是 False,其他非 0 的都是 True
  2. 在 int 中,只有 x = 0 的时候才存在 -x 和 +x 相等的情况
  3. (((~x +1) | x) >> 31) 可以区分出 x 是否是 0,若是 x = 0 则结果 0,若是 x != 0 则结果为 -1
  4. 在 3 步骤的基础上执行 (((~x +1) | x) >> 31) +1,得到解题结果

解题方案:

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

第十题

题目:

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

解题思路:

  1. 解题的核心点在于如何利用 x 构造 False,如何利用 x 构造 True
  2. int a =(((!x) << 31) >> 31),利用结果来表示 x 等于 False 的情况
  3. 在 2步骤的基础上,int b = (~a), 利用结果来表示 x 等于 True 的情况
  4. (b&y) + (a&z),得到解题答案

解题方案:

int conditional(int x, int y, int z) {
    int a =(((!x) << 31) >> 31);
    int b = (~a);
  return (b&y) + (a&z);
}

第十一题

题目:

/*
 * isPower2 - returns 1 if x is a power of 2, and 0 otherwise
 *   Examples: isPower2(5) = 0, isPower2(8) = 1, isPower2(0) = 0
 *   Note that no negative number is a power of 2.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 4
 */
int isPower2(int x) {
    return 2;
}

解题思路:

  1. 2的次幂数对应二进制表示应该只有 1 位 1,其余位置全部都是0,重点是如何判断一个数的二进制表示只有一个 1,然后再处理好负数和 0 的情况
  2. x 的二进制表示只有一个 1 那么会有这个规律 x &(x-1) = 0x0,由于题目不能使用 - 号,所以转换成 !(x & (x + (~0) ))
  3. 在 2 步骤的基础上,!(x &(x-1)) 的结果可以判断 x 是否为 2 的幂
  4. (!(x >> 31)) 可以判断 x 是否为负数
  5. 在 4 步骤的基础上执行 (!(x >> 31)) & (~(!x))) 可以判断 x 是否为 0
  6. ( !! ( x ^ 0x0 ) ) 可以判断 x 是否 0
  7. (!(x & (x + (~0))) & (!(x >> 31)) & (!!(x ^ 0x0))) ,将 x 是否为 2 的幂,判断 x 是否为负数 和 x 是否 0 ,3个判断进行 & 操作,得到解题答案

解题方案:

int isPower2(int x) {
    return (!(x & (x + (~0))) & (!(x >> 31)) & (!!(x ^ 0x0)));
}

参考

  1. 华盛顿大学的 CSE 351 课程 The Hardware / Software Interface
    https://courses.cs.washington.edu/courses/cse351/17wi/videos.html
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • 一、实验目的 学习使用 weka 中的常用分类器,完成数据分类任务。 二、实验内容 了解 weka 中 explo...
    yigoh阅读 8,426评论 5 4
  • TF API数学计算tf...... :math(1)刚开始先给一个运行实例。tf是基于图(Graph)的计算系统...
    MachineLP阅读 3,431评论 0 1
  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,719评论 0 33
  • 有这样一种需求,给文字画上删除线,从简单点来讲,一句代码的事情: 但是这货有缺陷,就是只同文字的长度相关联,文字多...
    Axiba阅读 652评论 0 0
  • 八六年十二月十八日下午,曹奇来找我:“车间里反映,最近来的薄膜片基中个别卷又有些厚薄不匀的现象。”我立即接口:“曹...
    陈家老爷爷阅读 250评论 0 0