神奇算法小集合
来源:互联网 发布:kill me heal me 知乎 编辑:程序博客网 时间:2024/06/09 22:49
神奇算法小集合
整理一些今天看到的比较神奇的算法,可以拓宽下自己的思维和视野。
一、一个Float类型的绝对值
一个数值的绝对值可以通过与符号位的按位与操作来实现,对于IA32 32bit处理器,符号位是0x80000000,对于IA32 64bit来说,符号位是0x8000000000000000。下面代码为double类型的取绝对值操作。
- double x;
- /* make x = abs(x) */
- *(((int *) &x) + 1) &= 0x7fffffff;
二、指针对齐
指针的向上和向下对齐的操作可通过以下代码实现,代码中,a向b对齐,且b是2的指数次方:
- //向下对齐
- (a & ~(b-1)); //~(b-1) == -b,所以也可以写成如下形式
- (a & -b);
- //向上对齐
- ((a + (b-1)) & -b)
- a=((typeof(a))(((int)(((void *)malloc(c+(b-1)))+(b-1)))&-b))
下面,看几个神奇的操作:
- (x+y) = ((x&y)+(x|y)) = ((x^y)+2*(x&y));
- //那么,(x+y)/2可通过下面的操作实现
- (x&y)+((x^y)/2) = (x&y)+((x^y)>>1)
- //上一行代码的有点是这样不会导致溢出
一个整数按位倒置可通过以下代码实现:
- unsigned int
- reverse(register unsigned int x)
- {
- x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
- x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
- x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
- x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
- return((x >> 16) | (x << 16));
- }
- //此函数也可重写为如下函数
- unsigned int
- reverse(register unsigned int x)
- {
- register unsigned int y = 0x55555555;
- x = (((x >> 1) & y) | ((x & y) << 1));
- y = 0x33333333;
- x = (((x >> 2) & y) | ((x & y) << 2));
- y = 0x0f0f0f0f;
- x = (((x >> 4) & y) | ((x & y) << 4));
- y = 0x00ff00ff;
- x = (((x >> 8) & y) | ((x & y) << 8));
- return((x >> 16) | (x << 16));
- }
Float类型数据的比较通过如下编码实现:
- #define FasI(f) (*((int *) &(f)))
- #define FasUI(f) (*((unsigned int *) &(f)))
- #define lt0(f) (FasUI(f) > 0x80000000U) //小于0
- #define le0(f) (FasI(f) <= 0) //小于等于0
- #define gt0(f) (FasI(f) > 0) //大于0
- #define ge0(f) (FasUI(f) <= 0x80000000U) //大于等于0
通常,双向链表中有两个指针,分别之前当前节点node的前驱指针prev和指向当前节点后继的指针next,如果每个链表节点中只能存储一个指针,如何实现双向链表呢?可通过将当前节点指针赋值为其前驱指针和后继指针的按位异或值(XOR)来实现。
不幸的是,在C语言中貌似没有对指针的异或定义。
七、除法取整
除法的向上和就近取证如下所示:
- (a+b-1)/b; //向上取整
- (a+(b/2))/b; //就近取整
有很多种传统方法,比如第k个Gray码可通过K^(K>>1)来实现,下面代码是Gray码与无符号二进制数的转换:
- unsigned int
- g2b(unsigned int gray)
- {
- gray ^= (gray >> 16);
- gray ^= (gray >> 8);
- gray ^= (gray >> 4);
- gray ^= (gray >> 2);
- gray ^= (gray >> 1);
- return(gray);
- }
整数乘法可以进行简单的转换,如x*y,如果x==5(4+1),则可通过如下方式来计算x*y:
- y2 = y + y;
- y4 = y2 + y2;
- result = y + y4;
- y4 = (y << 2);
- result = y + y4;
两个整数的最大值和最小值的计算可通过如下方式实现,其中x和y是2的补码形式:
- //x和y的最小值
- x+(((y-x)>>(WORDBITS-1))&(y-x));
- //x和y的最大值
- x-(((x-y)>>(WORDBITS-1))&(x-y));
可参加整数的常量乘法中的技巧来计算整数的指数次方,如果x==5(4+1),则通过下面方式来计算y的x次方:
- y2 = y * y;
- y4 = y2 * y2;
- result = y * y4;
通过以下代码实现整数的选择:
- //实现以下if和else语句,如
- if (a<b)
- x=c;
- else
- x=d;
- //通过下面代码实现此if else语句
- ((((a-b) >> (WORDBITS-1)) & (c^d)) ^ d)
- //如果x是2的幂次方,则此表达式为0,否则x不是2的幂次方
- (x&(x-1));
- unsigned int
- lzc(register unsigned int x)
- {
- x |= (x >> 1);
- x |= (x >> 2);
- x |= (x >> 4);
- x |= (x >> 8);
- x |= (x >> 16);
- return(WORDBITS - ones(x));
- }
- //求得x的最低有效bit
- (x^(x&(x-1)));
- //向下取整的版本
- unsigned int
- floor_log2(register unsigned int x)
- {
- x |= (x >> 1);
- x |= (x >> 2);
- x |= (x >> 4);
- x |= (x >> 8);
- x |= (x >> 16);
- #ifdef LOG0UNDEFINED
- return(ones32(x) - 1);
- #else
- return(ones32(x >> 1));
- #endif
- }
- //向上取整的版本,即需要判断x是否是2的幂次方
- unsigned int
- log2(register unsigned int x)
- {
- register int y = (x & (x - 1));
- y |= -y;
- y >>= (WORDBITS - 1);
- x |= (x >> 1);
- x |= (x >> 2);
- x |= (x >> 4);
- x |= (x >> 8);
- x |= (x >> 16);
- #ifdef LOG0UNDEFINED
- return(ones(x) - 1 - y);
- #else
- return(ones(x >> 1) - y);
- #endif
- }
- //Next Largest Power of 2
- unsigned int
- nlpo2(register unsigned int x)
- {
- x |= (x >> 1);
- x |= (x >> 2);
- x |= (x >> 4);
- x |= (x >> 8);
- x |= (x >> 16);
- return(x+1);
- }
- unsigned int
- msb32(register unsigned int x)
- {
- x |= (x >> 1);
- x |= (x >> 2);
- x |= (x >> 4);
- x |= (x >> 8);
- x |= (x >> 16);
- return(x & ~(x >> 1));
- }
一个多项式的表达式如x0+x1*x+x2*x*x+x3*x*x*x+...,其更加有效的计算可通过表达式x0+x*(x1+x*(x2+x*(x3+x*(...))))来替代。
二十、统计32位整数中1的个数
- unsigned int
- ones32(register unsigned int x)
- {
- /* 32-bit recursive reduction using SWAR...
- but first step is mapping 2-bit values
- into sum of 2 1-bit values in sneaky way
- */
- x -= ((x >> 1) & 0x55555555);
- x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
- x = (((x >> 4) + x) & 0x0f0f0f0f);
- x += (x >> 8);
- x += (x >> 16);
- return(x & 0x0000003f);
- }
二十一、不使用临时变量交换两个数的值
- //通过异或实现
- x ^= y; /* x' = (x^y) */
- y ^= x; /* y' = (y^(x^y)) = x */
- x ^= y; /* x' = (x^y)^x = y */
- //通过加减法实现
- x = x+y;
- x = x-y;
- y = x-y;
- //Trailing Zero Count
- unsigned int
- tzc(register int x)
- {
- return(ones((x & -x) - 1));
- }
- 神奇算法小集合
- 神奇算法小集合
- 算法小集合
- java小算法小集合
- 小集合
- JS代码小集合
- JS代码小集合
- JS代码小集合
- JS代码小集合
- JS代码小集合
- js代码小集合
- JS代码小集合
- JS代码小集合
- 中国俗语小集合~
- SEH资料小集合
- js小集合
- Myeclipse 快捷键小集合
- JS代码小集合
- Create Hot Selling Video Info Products In 20 Minutes!
- 电源引起的内存报警故障
- 【设计模式-抽象工厂】
- 利用 css3 的图形3d翻转效果应用demo
- More Exceptional C++ 笔记
- 神奇算法小集合
- 蓝牙随笔1
- 五个不为人知的ESC键妙用
- 电源引起的内存报警故障
- 一些Ruby惯用法
- 机房收费系统可行性研究----处理流程和数据流程
- java中保留小数的4种方法
- Solaris 设备状态检查常用命令
- 多进程通信(IPC)--匿名管道和命名管道