我的C实践(6):算术边界的检查
2016-07-29 00:00
375 查看
在计算机上进行算术运算时,经常会遇到结果溢出的情况,这就需要对运算的结果进行边界检查,判断其是否溢出,如果溢出,则要修正结果。下面用位运算来实现边界的检查。
/* arithbound.c:算术边界检测 */ #include <stdio.h> /* 下面的整数边界检测宏既适用于有符号整数,也适用于无符号整数 */ /* 判断是否有a<=x<=b */ #define lesseq_lessqe(x,a,b) ((unsigned)((x)-(a)) <= (unsigned)((b)-(a))) /* 判断是否有a<=x<b */ #define lesseq_less(x,a,b) ((unsigned)((x)-(a)) < (unsigned)((b)-(a))) /* 判断是否有a<x<=b */ #define less_lesseq(x,a,b) ((unsigned)((b)-(x)) < (unsigned)((b)-(a))) /* 判断是否有a<x<b */ #define less_less(x,a,b) ((unsigned)((x)-(a)-1) < (unsigned)((b)-(a)-1)) /* 下面是无符号整数运算的边界 */ /* 无符号整数加法x+y的边界[*s,*t]:其中x的边界为[a,b],y的边界为[c,d], 注意边界必须是正常的,即要有a<=b,c<=d */ inline void boundADDu(unsigned a, unsigned b, unsigned c, unsigned d, unsigned *s, unsigned *t){ *s=a+c; *t=b+d; if(*s>=a && *t<b){ /* a+c没有溢出但b+d溢出 */ *s=0; *t=0xffffffff; } } /* 无符号整数减法x-y的边界[*s,*t]:其中x的边界为[a,b],y的边界为[c,d] */ inline void boundSUBu(unsigned a, unsigned b, unsigned c, unsigned d, unsigned *s, unsigned *t){ *s=a-d; *t=b-c; if(*s>a && *t<=b){ /* a-d溢出但b-c没有溢出 */ *s=0; *t=0xffffffff; } } /* 无符号整数求负运算-x的边界[*s,*t]:其中x的边界为[a,b] */ inline void boundNEGu(unsigned a, unsigned b, unsigned *s, unsigned *t){ if(a==0 && b!=0){ *s=0; *t=0xffffffff; }else{ *s=-b; *t=-a; } } /* 带符号整数加法x+y的边界[*s,*t]:其中x的边界为[a,b],y的边界为[c,d] */ inline void boundADD(int a, int b, int c, int d, int *s, int *t){ unsigned u,v; *s=a+c; *t=b+d; /* (a&c&~(a+c))<0:表示a+c在负方向溢出,即a<0 && c<0 && (a+c)>=0; ~(b&d&~(b+d))<0:前面加了非,表示b+d在负方向不溢出 */ u=a & c & ~*s & ~(b & d & ~*t); /* (a^c|~(a^a+c))<0:表示a+c不溢出,即“a,c异号或a+c与a同号”(溢出条件的反面); (~b&~d&b+d)<0:表示b+d在正方向溢出,即“b>0 && c>0 && b+d<0” */ v=((a ^ c) | ~(a ^ *s)) & (~b & ~d & *t); if((u | v)<0){ /* a+c在负方向溢出且b+d在负方向不溢出,或a+c不溢出且b+d在正方向溢 */ *s=0x80000000; *t=0x7fffffff; } } /* 带符号整数减法x-y的边界[*s,*t]:其中x的边界为[a,b],y的边界为[c,d] 可重写y的边界为-d<=-y<=-c,并通过x+(-y)来求,即把上面代码中的c替 换成-d,把d替换成-c */ inline void boundSUB(int a, int b, int c, int d, int *s, int *t){ unsigned u,v; *s=a-d; *t=b-c; u=a & -d & ~*s & ~(b & -c & ~*t); v=((a ^ -d) | ~(a ^ *s)) & (~b & ~-c & *t); if((u | v)<0){ *s=0x80000000; *t=0x7fffffff; } } /* 带符号整数求负运算-x的边界[*s,*t]:其中x的边界为[a,b] */ inline void boundNEG(int a, int b, int *s, int *t){ if(a==0x80000000 && b==0x80000000) *s=*t=0x80000000; else if(a==0x80000000 && b!=0x80000000){ *s=0x80000000; *t=0x7fffffff; } else { *s=-b; *t=-a; } } /* 逻辑或操作的下界:针对的都是无符号类型 */ unsigned minORu(unsigned a, unsigned b, unsigned c, unsigned d){ unsigned m,temp; m=0x80000000; while(m!=0){ if(~a & c & m){ /* 如果当前位上a为0而c为1 */ temp=(a | m) & -m; /* 就把a上的这个0改为1,并把其后的所有位都改成0,注意-m仍为原来的m值 */ if(temp<=b) { a=temp; break; } /* 如果这种改变可行(即仍小于上界b),则退出循环 */ } else if(a & ~c & m){ /* 当前位上a为1而c为0的情况 */ temp=(c | m) & -m; if(temp<=d) { c=temp; break; } } m=m>>1; /* 改变不可行,则继续扫描下一位 */ } return a | c; } /* 逻辑或操作的上界 */ unsigned maxORu(unsigned a, unsigned b, unsigned c, unsigned d){ unsigned m,temp; m=0x80000000; while(m!=0){ if(b & d & m){ /* 当前位上b,d均为1 */ temp=b-m | m-1; /* 把其中一个(这里为b)的这个1改为0,并把其后所有位都改成1 */ if(temp>=a) { b=temp; break; } /* 如果改变可行,则退出循环 */ temp=d-m | m-1; /* 上面的改变不可行就在另一个边界上试试 */ if(temp>=c) { d=temp; break; } } m=m>>1; /* 改变不可行,则继承扫描下一位 */ } return b | d; } /* 逻辑与操作的下界和上界:利用a<=x<=b等价于~b<=~x<=~a,及DeMorgan律x&y=~(~x | ~y), 转换成逻辑或操作 */ inline unsigned minANDu(unsigned a, unsigned b, unsigned c, unsigned d){ return ~maxORu(~b,~a,~d,~c); } inline unsigned maxANDu(unsigned a, unsigned b, unsigned c, unsigned d){ return ~minORu(~b,~a,~d,~c); } /* 逻辑异或操作的下界:与minOR类似,只不过改变成功时不终止扫描,而是继续扫描下一位 */ unsigned minXORu(unsigned a, unsigned b, unsigned c, unsigned d){ unsigned m,temp; m=0x80000000; while(m!=0){ if(~a & c & m){ /* 如果当前位上a为0而c为1 */ temp=(a | m) & -m; /* 就把a上的这个0改为1,并把其后的所有位都改成0,注意-m仍为原来的m值 */ if(temp<=b) { a=temp; } /* 如果这种改变可行(即仍小于上界b),则继续扫描下一位 */ } else if(a & ~c & m){ /* 当前位上a为1而c为0的情况 */ temp=(c | m) & -m; if(temp<=d) { c=temp; } } m=m>>1; /* 扫描下一位 */ } return a ^ c; } /* 逻辑异或操作的上界:与maxOR类似,只不过对每一位(不管是0还是1)都尝试作改变, 改变成功时不终止扫描,而是继续扫描下一位 */ unsigned maxXORu(unsigned a, unsigned b, unsigned c, unsigned d){ unsigned m,temp; m=0x80000000; while(m!=0){ temp=b-m | m-1; /* 把其中一个(这里为b)的当前位取反,并把其后所有位都改成1 */ if(temp>=a) b=temp; /* 改变可行,则继续扫描下一位 */ else{ temp=d-m | m-1; /* 上面的改变不可行就在另一个边界上试试 */ if(temp>=c) d=temp; } m=m>>1; /* 扫描下一位 */ } return b ^ d; } /* 逻辑非操作的下界和上界:a<=x<<b等价于~b<=~x<=~a */ inline unsigned minNOTu(unsigned a, unsigned b){ return ~b; } inline unsigned maxNOTu(unsigned a, unsigned b){ return ~a; } /* 下面带符号整数的逻辑操作边界 */ /* 逻辑或操作的下界:带符号整数 */ int minOR(int a, int b, int c, int d){ int m=(a>>28 | b>>29 | c>>30 | d>>31) & 0x0000000f; switch(m){ case 0x0000000f: case 0x0000000c: case 0x00000003: case 0x00000000: return minORu(a,b,c,d); case 0x0000000e: return a; case 0x0000000b: return c; case 0x0000000a: return a<=c ? a : c; case 0x00000008: return minORu(a,0xffffffff,c,d); case 0x00000002: return minORu(a,b,c,0xffffffff); } } /* 逻辑或操作的上界:带符号整数 */ int maxOR(int a, int b, int c, int d){ int m=(a>>28 | b>>29 | c>>30 | d>>31) & 0x0000000f; switch(m){ case 0x0000000f: case 0x0000000c: case 0x00000003: case 0x00000000: return maxORu(a,b,c,d); case 0x0000000e: case 0x0000000b: return -1; case 0x0000000a: return maxORu(0,b,0,d); case 0x0000008: return maxORu(0,b,c,d); case 0x00000002: return maxORu(a,b,0,d); } } /* 逻辑与操作的下界和上界:带符号整数。利用a<=x<=b等价于~b<=~x<=~a, 及DeMorgan律x&y=~(~x | ~y),转换成逻辑或操作 */ inline int minAND(int a, int b, int c, int d){ return ~maxOR(~b,~a,~d,~c); } inline int maxAND(int a, int b, int c, int d){ return ~minOR(~b,~a,~d,~c); } /* 带符号整数的逻辑异或操作边界:计算比较复杂 */ /* 逻辑非操作的下界和上界:带符号整数。a<=x<<b等价于~b<=~x<=~a */ inline int minNOT(int a, int b){ return ~b; } inline int maxNOT(int a, int b){ return ~a; } #if 1 int main(){ int a=0x00000002, b=0x00000004, c=0x00000009, d=0x00000014; printf("minORu: 0x%x/n",minORu(a,b,c,d)); printf("maxORu: 0x%x/n",maxORu(a,b,c,d)); printf("minANDu: 0x%x/n",minANDu(a,b,c,d)); printf("maxANDu: 0x%x/n",maxANDu(a,b,c,d)); printf("minXORu: 0x%x/n",minXORu(a,b,c,d)); printf("maxXORu: 0x%x/n",maxXORu(a,b,c,d)); printf("minNOTu: 0x%x/n",minNOTu(a,b)); printf("maxNOTu: 0x%x/n",maxNOTu(a,b)); printf("minOR: 0x%x/n",minOR(a,b,c,d)); printf("maxOR: 0x%x/n",maxOR(a,b,c,d)); printf("minAND: 0x%x/n",minAND(a,b,c,d)); printf("maxAND: 0x%x/n",maxAND(a,b,c,d)); /* printf("minXOR: 0x%x/n",minXOR(a,b,c,d)); printf("maxXOR: 0x%x/n",maxXOR(a,b,c,d)); */ printf("minNOT: 0x%x/n",minNOT(a,b)); printf("maxNOT: 0x%x/n",maxNOT(a,b)); return 0; } #endif
相关文章推荐
- dbm数据库源代码分析(8):hash.c和findkey.c
- MVC模式
- Linux Socket编程
- Java并发与多线程教程(3)
- JVM调优总结(2):调优方法
- OpenStack快速入门
- 深入理解Java类加载器(1):Java类加载原理解析
- Oracle官方并发教程(2)
- 程序时间空间开销测试
- JVM调优总结(2):调优方法
- 浅析Java虚拟机结构与机制
- 位图数据结构的运用
- libxml2剖析(2):编译
- 深入理解Java注解(2):高级应用
- SQLite剖析(7):锁和并发控制
- 架构腐化之谜
- 先产品,再战略,最后是商业模式
- C标准库源码解剖(8):日期与时间函数time.h(续)
- C++ Primer学习系列(1):快速入门/变量和基本类型/标准库类型
- 搭建Eclipse C/C++开发环境