用C编写一个程序,使用递归来确定一个数是否为素数。获取高数值的堆栈溢出错误

用C编写一个程序,使用递归来确定一个数是否为素数。获取高数值的堆栈溢出错误,c,recursion,stack-overflow,C,Recursion,Stack Overflow,用C编写一个程序,使用递归来确定一个数是否为素数。它会一直工作,直到你尝试用一个大于9431的素数。高于该值的任何值都会导致堆栈溢出错误。我想知道是否有办法解决这个问题 我真的没有试过别的方法,只是看看它失败的次数,每次都不一样 //Remove scanf error #define _CRT_SECURE_NO_WARNINGS //Preprocessor directives #include<stdio.h> #include<stdlib.h> //Rec

用C编写一个程序,使用递归来确定一个数是否为素数。它会一直工作,直到你尝试用一个大于9431的素数。高于该值的任何值都会导致堆栈溢出错误。我想知道是否有办法解决这个问题

我真的没有试过别的方法,只是看看它失败的次数,每次都不一样

//Remove scanf error
#define _CRT_SECURE_NO_WARNINGS

//Preprocessor directives
#include<stdio.h>
#include<stdlib.h>

//Recursion function
int PrimeCheck(int choice, int i)
{
    //Check if integer i is reduced to 1
    if (i == 1)
    {
        return 0;
    }
    else
    {
        //Check to see if number choice is divisible by value i
        if (choice % i == 0)
        {
            return 1;
        }

        //Call the function again but reduce the second variable by 1
        else
        {
            return PrimeCheck(choice, i - 1);
        }
    }
}//End PrimeCheck function

//Main function
main()
{
    //Assign needed variables
    int choice, num;

    //ask for user input
    printf("Please enter a number between 2 and %i:", INT_MAX);
    scanf("%i", &choice);

    //Check for numbers outside the range
    if (choice < 2 || choice > INT_MAX)
    {
        printf("Please try again and enter a valid number.\n");
        system("pause");
        return 0;
    }

    //Call the PrimeCheck "looping" function
    num = PrimeCheck(choice, choice / 2);

    //Display result for the user
    if (num == 0)
    {
        printf("%i is a prime number.\n", choice);
    }

    else
    {
        printf("%i is NOT a prime number.\n", choice);
    }

    system("pause");
}//End main
//删除扫描错误
#定义\u CRT\u安全\u无\u警告
//预处理器指令
#包括
#包括
//递归函数
int PrimeCheck(int选择,int i)
{
//检查整数i是否减少为1
如果(i==1)
{
返回0;
}
其他的
{
//检查数字选择是否可被值i整除
如果(选项%i==0)
{
返回1;
}
//再次调用该函数,但将第二个变量减少1
其他的
{
返回PrimeCheck(选项,i-1);
}
}
}//结束检查功能
//主要功能
main()
{
//分配所需的变量
int选择,num;
//请求用户输入
printf(“请输入一个介于2和%i之间的数字:”,INT_MAX);
scanf(“%i”和“选择”);
//检查是否有超出范围的数字
如果(选项<2 | |选项>INT|u MAX)
{
printf(“请重试并输入有效数字。\n”);
系统(“暂停”);
返回0;
}
//调用PrimeCheck“循环”函数
num=PrimeCheck(选项,选项/2);
//为用户显示结果
如果(num==0)
{
printf(“%i是质数。\n”,选项);
}
其他的
{
printf(“%i不是质数。\n”,选项);
}
系统(“暂停”);
}//端干管
输出应为“\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
9431以上的实际输出是堆栈溢出错误。

一个帮助,减少测试

PrimeCheck(选项,选项/2)sqrt(choice)
次时,code>迭代大约
choice/2次

而不是从
choice/2开始

PrimeCheck(choice, sqrt(choice));
更好的代码可以避免较小的舍入误差和整数截断

PrimeCheck(choice, lround(sqrt(choice)));
或者,如果您可以访问整数平方根函数:

PrimeCheck(choice, isqrt(choice));
对于
9431
,这将使堆栈深度减少约50倍,并加快程序速度


速度性能提示。而不是从
choice/2
sqrt(choice)
向下迭代到1。从2上升到
sqrt(选项)
。非素数的检测速度会快得多


样品

#include <stdbool.h>
#include <stdio.h>

bool isprimeR_helper(unsigned test, unsigned x) {
  // test values too large, we are done
  if (test > x/test ) {
    return true;
  }
  if (x%test == 0) {
    return false; // composite
  }
  return isprimeR_helper(test + 2, x);
}

bool isprimeR(unsigned x) {
  // Handle small values
  if (x <= 3) {
    return x >= 2;
  }
  // Handle other even values
  if (x %2 == 0) {
    return false;
  }
  return isprimeR_helper(3, x);
}

int main(void) {
  for (unsigned i = 0; i < 50000; i++) {
    if (isprimeR(i)) {
      printf(" %u", i);
    }
  }
  printf("\n");
}

实施说明

如果(测试*测试>x)
,则不要使用
。使用
test>x/test

  • test*test
    可能溢出<代码>x/测试
将不会

  • 好的编译器将看到附近的
    x/test
    x%test
    ,并将两者作为一个操作进行有效计算。因此,如果代码具有
    x%test
    ,那么
    x/test
    的成本通常可以忽略不计


  • (a)此程序不包括
    ,因此我们预计不会定义
    INT\u MAX
    ,编译也会失败。这就是您正在编译的源代码吗?(b) 您正在使用哪个编译器,以及使用哪些开关进行编译?顺便说一句,
    choice>INT\u MAX
    不可能计算为true,因为
    choice
    是一个
    INT
    ,因此它的最大可能值是
    INT\u MAX
    。无论如何,如果您使用
    -O3
    进行编译(甚至
    -O2
    )GCC很乐意优化尾部调用,并将递归函数编译成一个简单的循环。递归不再出现堆栈溢出:p当您为超过
    INT\u MAX
    的数字输入数字时,
    scanf
    会自动失败;它不会将数字的值放入
    选项
    。它不能,因为
    choice
    不能容纳这样的数字。根据C 2018 7.21.6.2 10,当结果不能在对象中表示时,行为是未定义的。@DanielNudelman代码是非常错误的。整数溢出恰好使它看起来正确,因为
    int
    是一个有符号值,所以
    2147483648==-1<2
    。我明白了。非常感谢。对于像我这样的傻瓜来说,这些都是很好的信息。我真的很感激。:)
    2 3 5 7 11 13 17 19 ... 49991 49993 49999