文章目录
用与非门实现异或
与非门在两个输入都是 1 的时候才输出 0 ,异或是两个输入相同为 0,不同为 1。
描述一下就是首先这两个输入进行与非,得到的结果分别和两个输入进行与非,最后两个结果再进行与非。
怎么得出来的???参考 https://cs.stackexchange.com/questions/43342/how-to-construct-xor-gate-using-only-4-nand-gate
A ⊕ B = A B ‾ ( A + B ) = A B ‾ A + A B ‾ B = ( A B ‾ A ) ( A B ‾ B ) ‾ \begin{aligned} A\oplus B&=\overline{AB}(A+B)\\ &=\overline{AB}A+\overline{AB}B\\ &=\overline{(\overline{AB}A)(\overline{AB}B)} \end{aligned} A⊕B=AB(A+B)=ABA+ABB=(ABA)(ABB)
/*
* bitXor - x^y using only ~ and &
* Example: bitXor(4, 5) = 1
* Legal ops: ~ &
* Max ops: 14
* Rating: 1
*/
int bitXor(int x, int y) {
int naxy = ~(x&y);
int na1 = ~(x&naxy);
int na2 = ~(y&naxy);
return ~(na1&na2);
}
求用补码表示的最小 integer
two’s complement integer 就是补码。
这个很简单。
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return 1<<31;
}
判断该补码是否是最大值
用了 8 个 operator ,思路是最大值 0x7fffffff
加一和翻转是相同的(要排除 0xffffffff
)
/*
* isTmax - returns 1 if x is the maximum, two's complement number,
* and 0 otherwise
* Legal ops: ! ~ & ^ | +
* Max ops: 10
* Rating: 1
*/
int isTmax(int x) {
return (!((~x)^(x+1)))&!!(~x);
}
判断所有奇数位是否为 1
最低位编号为 0
这个也很简单,但是不能直接用 0xaaaaaaaa
,因为只能用 Integer constants 0 through 255 (0xFF), inclusive. 但是没有问题!构造一个就行了,总共用了 7 个 op
/*
* allOddBits - return 1 if all odd-numbered bits in word set to 1
* where bits are numbered from 0 (least significant) to 31 (most significant)
* Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 12
* Rating: 2
*/
int allOddBits(int x) {
int m0=0xaa;
int m1=(m0<<8)|m0;
int m=(m1<<16)|m1;
return !((m&x)^m);
}
输出 -x
简单。取反加一
/*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return ~x+1;
}
判断是否为 ‘0’-‘9’ 的 ASCII
即判断是否在 0x30-0x39
之间
先判断最高的 24 位是不是 0x3
:!((x>>4)^0x3)
,然后判断最低的 4 位,有两种情况:
- 最高位是
0
,此时表示 0 到 7 :!(x&0x8)
- 最高位是
1
,此时表示 8 到 9:!(x&0x6)
(判断 2,3 位同时为 0)
还是很妙的,用了 9 个 op
/*
* isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
* Example: isAsciiDigit(0x35) = 1.
* isAsciiDigit(0x3a) = 0.
* isAsciiDigit(0x05) = 0.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 3
*/
int isAsciiDigit(int x) {
return !((x>>4)^0x3)&(!(x&0x8)|!(x&0x6));
}
实现 x ? y : z
这里只要判断 x 是否为 0 ,首先取反,然后向左移 31 位,将判断值移到最高位,然后再向右移 31 位,假如判断值为 1 的话,由于默认右移是算术移位,因此左右移位后就全变成了 1。总共用了 7 个 op
/*
* 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) {
int t=!x;
t=(t<<31)>>31;
return (t&z)|(~t&y);
}
实现 ≤ \le ≤
首先判断两个数的符号是否相同,假如符号不同且 x 为负数,那么小于等于成立。
再考虑符号相同的情况,此时应当有 y-x>=0
即 y+(~x+1)>=0
。
分成这两步处理可以防止计算 y+(~x+1)
时发生溢出。用了 15 个 op
/*
* isLessOrEqual - if x <= y then return 1, else return 0
* Example: isLessOrEqual(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
int isLessOrEqual(int x, int y) {
int sx=!(x>>31); // x < 0 : 0
int sy=!(y>>31);
int ds=sx^sy;
int xn=ds&!sx;
int le=!ds&!((y+(~x+1))>>31); // y-x >= 0
return xn|le;
}
实现逻辑非
思路是把每一位或起来,判断最后是否为 1。刚好用了 12 个 op
/*
* logicalNeg - implement the ! operator, using all of
* the legal operators except !
* Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
* Legal ops: ~ & ^ | + << >>
* Max ops: 12
* Rating: 4
*/
int logicalNeg(int x) {
x=x|(x>>1);
x=x|(x>>2);
x=x|(x>>4);
x=x|(x>>8);
x=x|(x>>16);
return x&0x1^0x1;
}
最少用几位补码表示
这题还是很有意思的,参考了别人的写法。首先把负数进行翻转求解(一个正数需要的位数就是找其最高的 1,一个负数需要的位数就是找其最高的 0),然后依次判断最高 16 位是否全为 0 ,否则的话就至少需要十六位,然后将原 x 向右移掉这已经计算过的十六位,直至 8 位、4 位、2 位、1 位 等。详见代码。最后加的 1 是符号位(0,-1 可以认为只有符号位)
用了 36 个 op
/* howManyBits - return the minimum number of bits required to represent x in
* two's complement
* Examples: howManyBits(12) = 5
* howManyBits(298) = 10
* howManyBits(-5) = 4
* howManyBits(0) = 1
* howManyBits(-1) = 1
* howManyBits(0x80000000) = 32
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 90
* Rating: 4
*/
int howManyBits(int x) {
int s,b16,b8,b4,b2,b1,b0;
s=x>>31;
x=(s&~x)|(~s&x);
b16=!!(x>>16)<<4;
x=x>>b16;
b8=!!(x>>8)<<3;
x=x>>b8;
b4=!!(x>>4)<<2;
x=x>>b4;
b2=!!(x>>2)<<1;
x=x>>b2;
b1=!!(x>>1);
x=x>>b1;
b0=x;
return b16+b8+b4+b2+b1+b0+1;
}
浮点数乘 2
输入 32 bit ,表示的形式是单精度浮点数,其格式如下:
根据条件判断即可,用了 15 个 op:
/*
* floatScale2 - Return bit-level equivalent of expression 2*f for
* floating point argument f.
* Both the argument and result are passed as unsigned int's, but
* they are to be interpreted as the bit-level representation of
* single-precision floating point values.
* When argument is NaN, return argument
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
unsigned floatScale2(unsigned uf) {
// uf==+-0
if(uf==0||uf==0x80000000)return uf;
// NaN
if(((uf>>23)&0xff)==0xff)return uf;
// denormalized values
if(((uf>>23)&0xff)==0)return (uf&(1<<31))|(uf<<1);
// exp + 1
return uf+(1<<23);
}
浮点数转 int
/*
* floatFloat2Int - Return bit-level equivalent of expression (int) f
* for floating point argument f.
* Argument is passed as unsigned int, but
* it is to be interpreted as the bit-level representation of a
* single-precision floating point value.
* Anything out of range (including NaN and infinity) should return
* 0x80000000u.
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
int floatFloat2Int(unsigned uf) {
int s,e,f;
s=(uf>>31)&0x1;
e=(uf>>23)&0xff;
if((uf==0)||(uf==0x80000000))return 0;
if(e==0)return 0;
if(e==0xff)return 0x80000000u;
f=(uf&0x7fffff)|0x800000;
e-=127; // minus bias
if(e<0)return 0;
if(e>30)return 0x80000000u;
if(e>23)f=f<<(e-23);
if(e<23)f=f>>(23-e);
if(s) f=~f+1;
return f;
}
浮点数 2.0^x
这个很简单啦,注意小于 2 − 126 2^{-126} 2−126 时考虑使用 denormalized 方式进行表示。
用了 16 个 op
/*
* floatPower2 - Return bit-level equivalent of the expression 2.0^x
* (2.0 raised to the power x) for any 32-bit integer x.
*
* The unsigned value that is returned should have the identical bit
* representation as the single-precision floating-point number 2.0^x.
* If the result is too small to be represented as a denorm, return
* 0. If too large, return +INF.
*
* Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while
* Max ops: 30
* Rating: 4
*/
unsigned floatPower2(int x) {
if(x<-149)return 0;
if(x>=-149&&x<-126)return 1<<(149+x);
if(x>=-126&&x<=127)return (x+127)<<23;
return 0xff<<23;
}
来一张测试图~
Correctness Results Perf Results
Points Rating Errors Points Ops Puzzle
1 1 0 2 8 bitXor
1 1 0 2 1 tmin
1 1 0 2 8 isTmax
2 2 0 2 7 allOddBits
2 2 0 2 2 negate
3 3 0 2 9 isAsciiDigit
3 3 0 2 7 conditional
3 3 0 2 15 isLessOrEqual
4 4 0 2 12 logicalNeg
4 4 0 2 36 howManyBits
4 4 0 2 15 floatScale2
4 4 0 2 22 floatFloat2Int
4 4 0 2 16 floatPower2