您的位置:首页 > 其它

我的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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: