为什么我的按位除法函数会产生分段错误?

时间:2012-10-04 04:13:09

标签: c segmentation-fault bit-manipulation

我的代码在下面,它适用于大多数输入,但我注意到对于非常大的数字(2147483647除以特定示例的2),我得到分段错误并且程序停止工作。请注意,badd()和bsub()函数分别只是添加或减去整数。

unsigned int bdiv(unsigned int dividend, unsigned int divisor){  
    int quotient = 1; 
    if (divisor == dividend)
    {
        return 1; 
    }
    else if (dividend < divisor)
    {   return -1; }// this represents dividing by zero

    quotient = badd(quotient, bdiv(bsub(dividend, divisor), divisor));

    return quotient;
}

我的bmult()函数也遇到了一些麻烦。它适用于某些值,但程序失败的值为-8192次3.此功能也会列出。在此先感谢您的帮助。我真的很感激!

int bmult(int x,int y){
    int total=0;
    /*for (i = 31; i >= 0; i--)
    {
        total = total << 1;
        if(y&1 ==1)
        total = badd(total,x);
    }
    return total;*/ 
    while (x != 0)
    {
        if ((x&1) != 0)
        {
            total = badd(total, y);
        }
        y <<= 1;
        x >>= 1;
    }
    return total; 
}

2 个答案:

答案 0 :(得分:1)

bdiv的问题很可能是由递归深度引起的。在你给出的例子中,你将把大约1073741824帧放到堆栈上,基本上耗尽你分配的内存。

事实上,这个函数没有理由需要递归。我可以很容易地转换为迭代解决方案,缓解堆栈问题。

答案 1 :(得分:1)

在乘法中,此行会溢出并截断y,因此badd()输入错误:

y<<=1;

这一行:

x>>=1;

不能很好地为负x工作。大多数编译器会在这里进行所谓的算术移位,这就像一个常规移位,0移位到最高位,但是有一个扭曲,最重要的位不会改变。所以,任何负值转移最终都会给你-1。向右移动的-1将保持为-1,从而导致乘法中出现无限循环。

您不应该使用该算法将无符号整数相乘以乘以有符号整数。如果它在核心中使用签名类型,则不太可能正常工作(如果有的话)。

如果要乘以有符号整数,可以先使用无符号类型对无符号整数进行乘法运算。然后你可以将它用于有符号乘法。这几乎适用于所有系统,因为它们使用带符号整数的2的补码表示。

示例(假设16位2的补码整数):

-1 * +1 - &gt; 0xFFFF * 1 = 0xFFFF - &gt;转换回签名 - &gt; -1
-1 * -1 - &gt; 0xFFFF * 0xFFFF = 0xFFFE0001 - &gt;截断为16位&amp;转换为签名 - &gt; 1

在分区中有以下两行

else if (dividend < divisor)
{   return -1; }// this represents dividing by zero

是完全错的。想想,1/2是多少?它是0,不是-1或(unsigned int)-1。

此外,UINT_MAX / 1多少钱?它是UINT_MAX。因此,当您的除法函数返回UINT_MAX(unsigned int)-1时,您将无法区分,因为这两个值是相同的。你真的应该使用不同的机制来通知调用者溢出。

哦,当然,这一行:

quotient = badd(quotient, bdiv(bsub(dividend, divisor), divisor));
当预期商数很大时,

会导致堆栈溢出。不要递归地这样做。至少,请使用循环。