如何在C ++中处理这个分段错误?

时间:2014-03-07 16:31:11

标签: c++ segmentation-fault factorial

我需要计算一个大质数的数的阶乘。 我的程序可以达到某些值,但是当我达到比程序中提到的值更高的值时,它会失败(分段错误)。

如何让这个程序运作?

非常感谢

#define LL unsigned long long
#define ull unsigned long long

const LL mod=1000000009;

LL arr[1048580];

inline ull mulMod(ull a,ull b,ull c)
{
    if(a<=1000000000ULL && b<=1000000000ULL)
    {
        //cout<<((a%c)*(b%c))%c<<endl;
        ull ret = ((a%c)*(b%c))%c;
        return ret;
    }
    ull ret = 0ULL; a=a%c;

    while(b > 0ULL)
    {
        if(b&1ULL) ret = ((ret%c)+(a%c))%c;
        a = (a<<1ULL)%c;
        b>>=1ULL;
    }
    return ret%c;
}

LL fact(LL num)
{
    if(arr[num]==0)
    {
        arr[num]=mulMod(num,fact(num-1),mod);
        return arr[num];
    }
    return arr[num];
}


int main()
{
    arr[0]=1;
    cout<<fact(325720);

}

3 个答案:

答案 0 :(得分:3)

你有Stack Overflow!

段错误来自mulMod()的递归调用。

如果你想让它适用于大数字,你应该避免递归。一个简单的for循环实现:

LL fact2(LL num)
{
    int i;
    for (i = 1; i < num; ++i) {
        arr[num] = mulMod(num,arr[num-1],mod);
    }
    return arr[num];
}

答案 1 :(得分:1)

你可以:

  • 通过要求操作系统加载程序安排更大的堆栈大小限制来移动失败的阈值(例如,尝试来自Linux / Unix shell的ulimit命令 - 请参阅here) ,或

  • 重写您的算法或更改编译器优化选项,以便它实现tail recursion优化(如果您发现可能使用您的特定算法和编译器),或

  • 编写一个使用for / while而不是递归的迭代解决方案。

答案 2 :(得分:0)

您的代码存在三个关键问题。显而易见的是你遇到的堆栈溢出。另一个是你通过不填充数组来调用未定义的行为。第三,如果你调用函数fact的数字大于或等于1048580,你将调用未定义的行为。

通过跟踪数组大小和已设置的最后一个元素,有助于解决最后两个问题。

const LL arr_size = 1048580;
LL last_arr = 0;
LL arr[arr_size] = {1,0};

堆栈溢出问题是由对fact的递归(非尾递归)调用引起的。这可以成为一个循环。请注意,我还要防范超出数组大小的数字。

LL fact(LL num)
{   
    if (num >= arr_size) {
        LL result = fact(arr_size-1);
        for (LL ii = arr_size; ii <= num; ++ii) {
            result = mulMod(ii,result,mod);
        }   
        return result;
    }   

    if (num > last_arr) {
        for (LL ii = last_arr+1; ii <= num; ++ii) {
            arr[ii] = mulMod(ii,arr[ii-1],mod);
        } 
        last_arr = num;  
    }   

    return arr[num];
}   

注意:这是递归定义到迭代定义的直接转录。有更好的方法可以做到这一点。