免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123
最近访问板块 发新帖
楼主: zx_wing

再来个问题,如何检测整数溢出 [复制链接]

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
发表于 2006-12-21 15:29 |显示全部楼层
原帖由 zx_wing 于 2006-12-21 09:10 发表


如果要看寄存器,这里提供一个方法,限于x86。
乘法操作的的高32位放在寄存器edx里,执行完乘法后,检查edx是否为0,不为0即溢出。

X86不需要这么麻烦,不需要多一道比较,乘法结果如果edx不为0的时候,会设置一个标志位,具体哪个忘了

论坛徽章:
0
发表于 2006-12-21 15:45 |显示全部楼层
当然要预先做一些判断,
我只是提供一个思路

原帖由 r2007 于 2006-12-21 15:25 发表

是否没有考虑另一个方向的溢出?
char  -128    -    127
x=-100 y=-50 这种情况如何判断?
比如
最大数-x=127-(-100)=127+100 已经溢出,如何再和y相比?

论坛徽章:
0
发表于 2006-12-21 17:01 |显示全部楼层
原帖由 cjaizss 于 2006-12-21 15:29 发表

X86不需要这么麻烦,不需要多一道比较,乘法结果如果edx不为0的时候,会设置一个标志位,具体哪个忘了


这是因为没有考虑实际的操作性。
你设想一下,你要在一个函数里这样写,需要使用内嵌汇编,从gcc的内嵌语法来说,读寄存器比访问状态码容易多了。

论坛徽章:
0
发表于 2006-12-21 17:17 |显示全部楼层
原帖由 zx_wing 于 2006-12-20 17:49 发表
两个整数x和y,进行加或乘操作,如何检测结果是否溢出?
如果是无符号数,姑且就说怎么检测结果超过精度了嘛。(whyglinux 你看,害我打了这么多字!

为了方便,把数据类型限制成int或unsigned int。 ...


我也发一个哈,利用的很多朋友的思路。
可惜给程序的很少,其实很多时候看上去简单的事情并不一定简单,还是多动手好。

主要针对有符号数,大家看看

  1. int is_overflow(int a, int b, int op)
  2. {
  3.     if ( op == 1 ) //op == 1代表加法操作
  4.     {
  5.         if ( a > 0 && b > 0) //正溢出
  6.             return (int)(a + b) < a ? 1 : 0;
  7.         else if ( a < 0 && b < 0 ) //负溢出
  8.             return (int)(a + b) > a ? 1 : 0;
  9.         else    //不会溢出
  10.             return 0;
  11.     }
  12.     else //否则为乘法操作   
  13.     {
  14.         int rc = a * b;
  15.         if ( rc != 0 && (rc/a) != b )
  16.             return 1;
  17.         return 0;
  18.     }
  19. }
复制代码

[ 本帖最后由 zx_wing 于 2006-12-22 09:35 编辑 ]

论坛徽章:
0
发表于 2006-12-21 18:17 |显示全部楼层
int is_oveflow(val a, val b)
{
  return (a ? (b*a/a != b) : 0);
}

论坛徽章:
0
发表于 2006-12-22 02:26 |显示全部楼层

请批评指正

Case 1: 两个无符号整数相加,溢出发生在从最高位产生进位,以16位整数为例,检测方法为:
#define MSB 0x8000
#define MASK 0x7FFF
int overflow1(unsigned int a, unsigned int b)
{
   unsigned int s;
   s=(a>>1)+(b>>1);
   return (s&MSB);
}

Case 2: 有符号数相加:
1. 正数和负数相加不会产生溢出;
2. 只有两个正数或两个负数相加才会产生溢出;
当溢出发生时,一定是次高位向符号位产生进位。(1)首先需要检查两个数的符号是否相同,可以用“异或”操作,(a^b),当两个数符号相同时,最高位为0;(2)然后判断是否发生了次高位向符号位产生进位,s=(a&MASK)+(b&MASK), 如果s 的最高为1,则发生进位,因此
int overflow2(int a, int b)
{
   int s,f;
   f=(a^b);        // test if two numbers have the same sign
   s=(a & MASK)+(b & MASK);
   return (~f & s) & MSB;
}


测试: 以下程序用gcc编译并测试通过。
#include <stdio.h>

#define MSB 0x80000000
#define MASK 0x7FFFFFFF

int overflow1(unsigned int a, unsigned int b)
{
   unsigned int s;
   s=(a>>1)+(b>>1);
   return (s & MSB);
}

int overflow2(int a, int b)
{
   int s,f;
   f=(a^b);        // test if two numbers have the same sign
   s=(a & MASK)+(b & MASK);
   return (~f & s) & MSB;
}

int main()
{
   unsigned int ux1=0x7FFFFFF0;
   unsigned int ux2=12345;
   unsigned int ux3=0x8F000000;
   int x1= 0x7FFFFFF0;
   int x2= 32767;
   int x3= -32767;
   int x4= 0x8FFF0002;

   int flag;

   // test ux1+ux2, no overflow
   printf("The size of int is %d\n\n", sizeof(int));
   flag = overflow1(ux1, ux2);
   printf("%u + %u = %u    ", ux1, ux2, ux1+ux2);
   if (flag)
      printf("overflow\n");
   else
      printf ("No overflow\n");

   // test ux1+ux3, overflow
   flag = overflow1(ux1, ux3);
   printf("%u + %u = %u    ", ux1, ux3,ux1+ux3);
   if (flag)
      printf("overflow\n");
   else
      printf ("No overflow\n");

   // test x1+x2, overflow
   flag = overflow2(x1, x2);
   printf("%d + %d = %d    ", x1, x2, x1+x2);
   if (flag)
      printf("overflow\n");
   else
      printf ("No overflow\n");

   // test x1+x3, no overflow
   flag = overflow2(x1, x3);
   printf("%d + %d = %d    ", x1, x3, x1+x3);
   if (flag)
      printf("overflow\n");
   else
      printf ("No overflow\n");

   // test x1+x4, no overflow
   flag = overflow2(x1, x4);
   printf("%d + %d = %d    ", x1, x4, x1+x4);
   if (flag)
      printf("overflow\n");
   else
      printf ("No overflow\n");

   // test x3+x4, overflow
   flag = overflow2(x3, x4);
   printf("%d + %d = %d    ", x3, x4, x3+x4);
   if (flag)
      printf("overflow\n");
   else
      printf ("No overflow\n");

   return 0;
}

论坛徽章:
0
发表于 2006-12-22 09:06 |显示全部楼层
>> 如果是无符号数,姑且就说怎么检测结果超过精度了嘛。(whyglinux 你看,害我打了这么多字!)

C 的规定在这里是有些别扭。不过,你可以认为无符号数的这种情况是“超”(over)而不“溢”(flow)。

  1. #include <limits.h>

  2. int is_overflow_add_for_unsigned_int( unsigned int a, unsigned int b )
  3. {
  4.   return UINT_MAX - a < b;
  5. }

  6. int is_overflow_add_for_signed_int( int a, int b )
  7. {
  8.   return a >= 0 ? INT_MAX - a < b : INT_MIN - a > b;
  9. }

  10. int is_overflow_multiply_for_unsigned_int( unsigned int a, unsigned int b )
  11. {
  12.   return a == 0 ? 0 : UINT_MAX / a < b;
  13. }

  14. int is_overflow_multiply_for_signed_int( int a, int b )
  15. {
  16.   return a == 0 ? 0 :
  17.     a > 0 && b > 0 || a < 0 && b < 0 ? INT_MAX / a < b : INT_MIN / a > b;
  18. }
复制代码

论坛徽章:
0
发表于 2006-12-22 09:16 |显示全部楼层
#define MSB 0x80000000
#define MASK 0x7FFFFFFF

int overflow1(unsigned int a, unsigned int b)
{
   unsigned int s;
   s=(a>>1)+(b>>1);
   return (s & MSB);
}

如果
a =0xFFFFFFFF;
b = 0x0000001;
怎么样?

论坛徽章:
0
发表于 2006-12-22 09:20 |显示全部楼层
嘻嘻,补上结果
4294967295 + 1 = 0    No overflow

论坛徽章:
0
发表于 2006-12-22 17:23 |显示全部楼层
#define MSB 0x80000000
#define MASK 0x7FFFFFFF

int overflow1(unsigned int a, unsigned int b)
{
   unsigned int s;
   s=(a>>1)+(b>>1);
   return (s & MSB);
}

如果
a =0xFFFFFFFF;
b = 0x0000001;
怎么样?

很抱歉     s=(a>>1)+(b>>1);这句有bug.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP