bits的妙用

bits的妙用

本文主要讲解变成过程中可能用到的一些位运算以及位运算符使用的技巧

对于整型的操作

第n位置位

x | (1<<n)

第n位置0

x & ~(1<<n)

翻转第n位

x ^ (1<<n)

获取大于等于此数的最小的2次幂数

unsigned int v; //只有当v是 32 bit才奏效
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
比如:当v是63那么转换之后,v-->64
当v是64,那么转换之后,v不变

获取最大整数

int maxInt = ~(1 << 31);
int maxInt = (1 << 31) - 1;
int maxInt = (1 << -1) - 1;

获取最小整数

int minInt = 1 << 31;
int minInt = 1 << -1;

获取最大的长整型数

long maxLong = ((long)1 << 127) - 1;

乘2

n << 1; // n*2

除2

n >> 1; // n/2

乘2的n次幂

n << m;

除2的n次幂

n >> m;

判断两个数是否相等

此方法比普通的比较速率快35%

(a^b) == 0; // a == b
!(a^b) // 在判断语句中使用

检查是否为奇数

(n & 1) == 1;

交换两个数字

//版本 1
a ^= b;
b ^= a;
a ^= b;

//版本 2
a = a ^ b ^ (b = a)

获取绝对值

//版本 1
x < 0 ? -x : x;

//版本 2
(x ^ (x >> 31)) - (x >> 31);

得到两个数的最大值

b & ((a-b) >> 31) | a & (~(a-b) >> 31);

得到两个数的最小值

a & ((a-b) >> 31) | b & (~(a-b) >> 31);

检查两个数字是否有相同的符号

(x ^ y) >= 0;

反转一个数的符号

i = ~i + 1; // or
i = (i ^ -1) + 1; // i = -i

计算2的n次幂

2 << (n-1);

判断一个数是不是2的次幂

n > 0 && (n & (n - 1)) == 0;

m对2的n次幂取余

m & (n - 1);

计算两个数的平均数

(x + y) >> 1;
((x ^ y) >> 1) + (x & y);

获取n的第m位 (从低到高)

(n >> (m-1)) & 1;

n的第m位置为0 (从低到高)

n & ~(1 << (m-1));

检查x的第n位是否被置位

if (x & (1<<n)) {
 // 第n位被置位
} else {
  //第n位没有被置位
}

提取最右边的为1的位

x & (-x)
例如:70000 0000 0000 0000 0000 0000 0000 0111
经过运算之后 变为
0000 0000 0000 0000 0000 0000 0000 0001
640000 0000 0000 0000 0000 0000 0100 0000
经过运算之后:
0000 0000 0000 0000 0000 0000 0100 0000

提取最右边的为0的位(类比于上一个)

~x & (x+1)

使最右边的为0的位置为1

x | (x+1)

n + 1

-~n

n - 1

~-n

得到一个数的负数

~n + 1;
(n ^ -1) + 1;

if (x == a) x = b; if (x == b) x = a;

x = a ^ b ^ x;

浮点数

此部分大多数都来源于 fast inverse square root method.

把一个浮点数转化为一个bits数组 (unsigned uint32_t)

#include <stdint.h>
typedef union {float flt; uint32_t bits} lens_t;
uint32_t f2i(float x) {
  return ((lens_t) {.flt = x}).bits;
}

把一个bits数组转化为浮点数

float i2f(uint32_t x) {
  return ((lens_t) {.bits = x}).flt;
}

Approximate the bit-array of a positive float using frexp

frexp gives the 2n decomposition of a number, so that man, exp = frexp(x) means that man 2exp = x and 0.5 <= man < 1.*

man, exp = frexp(x);//or man= frexp(x,&exp);
return (uint32_t)((2 * man + exp + 125) * 0x800000);

------------------------------
double x = 666.400000;
    double man = 0;
    int exp = 0;
    //sprintf(x&(-x),"%d");
    //cout << (x&(-x)) << endl;
    man= frexp(x,&exp);
    printf("frexp(%f,&n)=%f,n=%d\n", x, man, exp)
---------------------------------
运行结果:
frexp(666.400000,&n)=0.650781,n=10
---------------------------------

Caveat: This will have at most 2-16 relative error, since man + 125 clobbers the last 8 bits, saving the first 16 bits of your mantissa.

字符串

转换为小写字母

OR by space => (x | ' ')
Result is always lowercase even if letter is already lowercase
eg. ('a' | ' ') => 'a' ; ('A' | ' ') => 'a'

转换为大写字母

AND by underline => (x & '_')
Result is always uppercase even if letter is already uppercase
eg. ('a' & '_') => 'A' ; ('A' & '_') => 'A'

反转大小写

XOR by space => (x ^ ' ')
eg. ('a' ^ ' ') => 'A' ; ('A' ^ ' ') => 'a'

返回在字母表中的位置

AND by chr(31)/binary('11111')/(hex('1F') => (x & "\x1F")
Result is in 1..26 range, letter case is not important
eg. ('a' & "\x1F") => 1 ; ('B' & "\x1F") => 2

返回在字母表中的位置 (只对大写字母有效):

AND by ? => (x & '?') or XOR by @ => (x ^ '@')
eg. ('C' & '?') => 3 ; ('Z' ^ '@') => 26

返回在字母表中的位置 (只对小写字母有效):

XOR by backtick/chr(96)/binary('1100000')/hex('60') => (x ^ '`')
eg. ('d' ^ '`') => 4 ; ('x' ^ '`') => 25

杂项

从R5G5B5 to R8G8B8 的快速像素转换

R8 = (R5 << 3) | (R5 >> 2)
G8 = (R5 << 3) | (R5 >> 2)
B8 = (R5 << 3) | (R5 >> 2)

Note: 使用其他字母会产生严重错误

参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值