标签:res ISE round lse oat 整数 com 有一个 转化
Rating: 1
int bitAnd(int x, int y) {
return ~((~x) | (~y));
}
根据德摩根定律,x&y <==> ~((~x) | (~y))
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) {
n = n << 3;
x = x >> n;
return x&(0xff);
}
令x右移8*n位,使得目标为变为二进制下最低的8位,在与0xff相与,将高位清零。
int logicalShift(int x, int n) {
int y = (1 << 31) >> n;
x = x >> n;
y = y << 1;
y = ~y;
return x&y;
}
先将x算术右移n位,再构造低n位为1,其余位均为0的y,返回x&y的值即为所求
int bitCount(int x) {
int count,tmp1,tmp2,tmp3,tmp4,tmp5;
count = 0;
tmp1 = (0x55) | (0x55 << 8);
tmp1 = tmp1 | (tmp1 << 16);
tmp2 = (0x33) | (0x33 << 8);
tmp2 = tmp2 | (tmp2 << 16);
tmp3 = (0x0f) | (0x0f << 8);
tmp3 = tmp3 | (tmp3 << 16);
tmp4 = (0xff) | (0xff << 16);
tmp5 = (0xff) | (0xff << 8);
count = (x & tmp1) + ((x >> 1) & tmp1);
count = (count & tmp2) + ((count >> 2) & tmp2);
count = (count & tmp3) + ((count >> 4) & tmp3);
count = (count & tmp4) + ((count >> 8) & tmp4);
count = (count & tmp5) + ((count >> 16) & tmp5);
return count;
}
本题难点在于只允许使用40个操作符,考虑采用二分法。先将相邻两位相加,再对上一步所得结果的每两位看作一个整体,将相邻位相加......以此类推。最终使用36个操作符。
int bang(int x) {
int tmp = (~x) + 1;
tmp = tmp | x;
tmp = tmp >> 31;
return tmp+1;
}
如果x非0,则x或-x必有一个最高为为1,将x|(-x)算术右移31位可得到所有位全为1的数,再+1即可得到0.
如果x为0,则x和-x最高为均为0,将x|(-x)算术右移31位得到的还是0,再+1即可得到1.
int tmin(void) {
return (1 << 31);
}
最小的二进制补码整数最高位为1,其余全为0.
int fitsBits(int x, int n) {
int shift = 33 + (~n);
return !(((x << shift) >> shift) ^ x);
}
假设n=3只有当0x11111...[1xx]
或0x00000...[0xx]
我们才能用n个二进制位来表式x.
先将x左移32-n位,再算术右移32-n位,然后与x异或,接着取“!”即可
int divpwr2(int x, int n) {
int sign,tmp;
sign = x >> 31;//判断符号
tmp = sign & ((1 << n) + (~0));
return (x+tmp) >> n;
}
如果x是正数,直接算术右移n位即可。
如果x是负数,算术右移n位后需要向上取整。
向上取整方法:
在算术右移之前加上一个低n位全为1,其余为全为0的数。
int negate(int x) {
return (~x)+1;
}
二进制补码求负数,直接取反加1即可
int isPositive(int x) {
return !!((~(x >> 31))&x);
}
如果符号位为1,~(x >> 31)可得到0x00000000。将0x00000000&x后可得到0,在取两次!!后依旧为0.
如果符号位为0,~(x >> 31)可得到0xffffffff。如果x为0,将0xffffffff&x后可得到0在取两次!!后依旧为0. 如果x>0,将0xffffffff&x后可得到x,在取两次!!后即可得到1.
int isLessOrEqual(int x, int y) {
int sign,ret1,ret2;
sign = (x^y) >> 31;
ret1 = ((~x+1+y)>>31)&(~sign);//如果x和y同号
ret2 = (y>>31) & sign;
return !(ret1|ret2);
}
本题难点在于如果直接用y-x>=0来判断,存在y-x溢出的情况。
但我们很容易发现,只有在y和x异号时才会出现溢出的情况,所以只需先判断y和x的符号,如果符号相同,则通过y-x是否非负来判断结果;如果符号不同,则直接判断符号位即可比较大小。
int ilog2(int x) {
int ret = 0;
ret = (!!(x >> 16)) << 4;
ret = ret + ((!!(x >> (ret + 8))) << 3);
ret = ret + ((!!(x >> (ret + 4))) << 2);
ret = ret + ((!!(x >> (ret + 2))) << 1);
ret = ret + (!!(x >> (ret + 1)));
return ret;
}
本题可以转化为寻找最高位的1在哪个位置的问题,很容易可以想到采用二分查找难点在于如何在不使用循环体的情况下实现二分。维护一个ret,先将32位二进制数x右移16位,判断移位后的结果是否为0来判断高16位是否含1.如果含1,最终结果必然在16~31之间则令ret+=16,然后再用同样方法以此类推。最终找到最高为1的位置。
unsigned float_neg(unsigned uf) {
unsigned tmp;
tmp = uf & (0x7fffffff);
if (tmp > 0x7f800000)
return uf;
return uf ^ (0x80000000);
}
如果uf 为nan,直接返回uf。否则直接将符号位取反即可。
unsigned float_i2f(int x) {
unsigned shiftLeft=0;
unsigned afterShift, tmp, flag;
unsigned absX=x;
unsigned sign=0;
if (x==0) return 0;
//if x < 0, sign = 1000...,abs_x = -x
if (x<0)
{
sign=0x80000000;
absX=-x;
}
afterShift=absX;
//count shift_left and after_shift
while (1)
{
tmp=afterShift;
afterShift<<=1;
shiftLeft++;
if (tmp & 0x80000000) break;
}
if ((afterShift & 0x01ff)>0x0100)
flag=1;
else if ((afterShift & 0x03ff)==0x0300)
flag=1;
else
flag=0;
return sign + (afterShift>>9) + ((159-shiftLeft)<<23) + flag;
}
整数转浮点数经典题。
如果x为0,直接return 0.
如果x为负数,记录符号,然后把x变为正数。
一直左移,直到溢出,并记录移位次数。
afterShift记录尾数部分,159-shiftleft表示阶码
如果大于一半进一,少于一半则舍弃,等于一半则向偶数舍入
unsigned float_twice(unsigned uf) {
unsigned f = uf;
if ((f & 0x7F800000) == 0)
f = ((f & 0x007FFFFF) << 1) | (0x80000000 & f);
else if ((f & 0x7F800000) != 0x7F800000)
f =f + 0x00800000;
return f;
}
如果阶码为0,则直接将尾数左移一位,如果尾数溢出则恰好移入阶码,再加上符号位即可。
如果阶码全为1,则直接返回f。
如果阶码不为0且不全为1,则直接给阶码+1。
标签:res ISE round lse oat 整数 com 有一个 转化
原文地址:https://www.cnblogs.com/mizersy/p/10690026.html