寻找素因数分解的程序

Posted

技术标签:

【中文标题】寻找素因数分解的程序【英文标题】:Program to find the prime factorization 【发布时间】:2020-11-13 16:41:03 【问题描述】:

我编写这段代码是为了找到一个数的素数分解。我只是无法弄清楚最后一部分。如果 x 作为 double 或 float 输入,则程序应打印错误消息并终止。我如何做到这一点?

#include <stdio.h>
int main()

int x, i;
printf("Enter an integer:  ");
scanf("%d", &x);

 if (x <= 1)

    return 1;

printf("The prime factorization of %d is ", x);
if (x > 1)

    while (x%2 == 0) 
     
        printf("2 "); 
        x = x / 2; 
     
     for ( i = 3; i < 1009; i = i + 2)
    
    while (x%i == 0) 
         
            printf("%d ",i); 
            x = x / i; 
        
    

return 0;

【问题讨论】:

您预计会发生什么?实际发生了什么?为什么你两次调用 scanf 到同一个变量? 您拨打scanf 两次 读取号码x。这应该发生吗? 这就是它在处理重复的scanf() 后输出的内容。一旦你阅读了来自stdin 的输入,它就消失了:你不能重复它。 通过编辑,该程序对我来说运行良好。请理解,非常欢迎编辑您的问题以修复发布过程中引入的错误或添加缺失的细节,但有意义地改变所提出问题的编辑往往不会受到好评。编辑贴出的代码修复cmets中指出的bug属于后一类。 读取完整的输入行(例如使用fgets,并使用strtol 转换字符串。strtol 函数包括验证字符串及其内容的功能,例如参见解析结束并检查它是否解析了整个字符串(有效整数)或不解析(无效整数,如浮点值)。 【参考方案1】:

您的起点应该涵盖所有需要和不需要的情况,因此您应该从用户那里获取float 号码,而不是int。然后,您应该检查数字的整个小数部分是否为0。也就是说,如果它们都等于0,则用户希望提供int数字而不是float

第一步是声明一个浮点数:

float y;

之后,从用户那里获取它的值:

scanf("%f", &y);

第二步是检查是int还是float。这一步有很多方法。例如,我发现 roundf() function 很有用。它接受一个float 数字并计算最接近该数字的整数。因此,如果最接近的整数是数字本身,则该数字必须是int。对吧?

if(roundf(y)!=y)

如果你确定是int,你可以进行第三步:将float类型转换为int类型。它被称为type-casting。对于程序的其余部分,此步骤是必需的,因为在您的算法中,您使用 int 类型操作数字,因此只需将其转换为 int

x = (int)y;

添加上面的行后,您可以使用您键入的其余代码。我给整个程序:

#include <stdio.h>
#include <math.h>
int main()

    int x,i;
    float y;
    printf("Enter an integer:  ");
    scanf("%f", &y);

    if(roundf(y)!=y)
        printf("%f is not an integer!",y);
        return 1;
    

    else
        x = (int)y;
    

    if (x <= 1)
    
        printf("%d <= 1",x);
        return 1;
    

    else
    
        printf("The prime factorization of %d is ", x);
        while (x%2 == 0)
        
            printf("2 ");
            x = x / 2;
        
        for ( i = 3; i < 1009; i = i + 2)
        
            while (x%i == 0)
            
                printf("%d ",i);
                x = x / i;
            
        
    
    return 0;

【讨论】:

【参考方案2】:

scanf() 的使用有点棘手,我会不惜一切代价避免使用它来扫描用户生成的输入。但是这里是关于如何获取scanf() 错误的简短概述

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int main(void)

   int x, i, scanf_return;

   printf("Enter an integer:  ");

   /* Reset "errno". Not necessary here, just in case. */
   errno = 0;
   /* scanf() returns a value in case of an error */
   scanf_return = scanf("%d", &x);
   /*
    * scanf() returns "EOF" if it didn't find all what you wanted or
    * and error happened.
    * It sets "errno" to the value of the actual error. See manpage
    * for all of the details.
    */
   if (scanf_return == EOF) 
      /*
       * The error is connected to the stream, so we can differ between
       * an error within scanf() and and error with the input stream
       * (here: stdin)
       */
      if (ferror(stdin)) 
         fprintf(stderr, "Something went wrong while reading stdin: %s\n", strerror(errno));
         exit(EXIT_FAILURE);
       else 
         /* e.g. a conversion error, a float instead of an integer, letters
            instead of a decimal number */
         fprintf(stderr, "Something went wrong within scanf()\n");
         exit(EXIT_FAILURE);
      
   
   /*
    * If no error occurred, the return holds the number of objects
    * scanf() was able to read. We only need one, but it would throw an
    * error if cannot find any objects, so the check is here for
    * pedagogical reasons only.
    */
   if (scanf_return != 1) 
      fprintf(stderr, "Something went wrong within scanf(): wrong number of objects read.\n");
      exit(EXIT_FAILURE);
   

   if (x <= 1) 
      fprintf(stderr, "Input must be larger than 1!\n");
      exit(EXIT_FAILURE);
   
   printf("The prime factorization of %d is ", x);
   /* No need for that test, x is already larger than one at this point. */
   /* if (x > 1)  */
   while (x%2 == 0) 
      printf("2 ");
      x = x / 2;
   
   for (i = 3; i < 1009; i = i + 2) 
      while (x%i == 0) 
         printf("%d ",i);
         x = x / i;
      
   
   /*  */
   /* Make it pretty. */
   putchar('\n');
   exit(EXIT_SUCCESS);

有效吗?

$ ./***_003 
Enter an integer:  1234
The prime factorization of 1234 is 2 617 
$ factor 1234
1234: 2 617
$ ./***_003 
Enter an integer:  asd
Something went wrong within scanf(): wrong number of objects read.
$ ./***_003 
Enter an integer:  123.123
The prime factorization of 123 is 3 41

不,它不起作用。为什么不?如果您要求scanf() 扫描一个整数,它会抓取所有连续的十进制数字(0-9),直到没有一个。小限定符“连续”很可能是您的问题的根源:带有小数部分的浮点数有一个小数点,这就是 scanf() 假定您想要的整数结束的点。检查:

 $ ./***_003 
 Enter an integer:  .123
 Something went wrong within scanf(): wrong number of objects read

你是怎么知道的? @weather-vane 提供了多种方法之一:检查整数之后的下一个字符是否是句点(或您选择的另一个小数分隔符):

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int main(void)

   int x, i, scanf_return;
   char c = -1;

   printf("Enter an integer:  ");

   /* Reset "errno". Not necessary here, just in case. */
   errno = 0;
   /* scanf() returns a value in case of an error */
   scanf_return = scanf("%d%c", &x, &c);
   /*
    * scanf() returns "EOF" if it didn't find all what you wanted or
    * and error happened.
    * It sets "errno" to the value of the actual error. See manpage
    * for all of the details.
    */
   if (scanf_return == EOF) 
      /*
       * The error is connected to the stream, so we can differ between
       * an error within scanf() and and error with the input stream
       * (here: stdin)
       */
      if (ferror(stdin)) 
         fprintf(stderr, "Something went wrong while reading stdin: %s\n", strerror(errno));
         exit(EXIT_FAILURE);
       else 
         /* e.g. a conversion error, a float instead of an integer, letters
            instead of a decimal number */
         fprintf(stderr, "Something went wrong within scanf()\n");
         exit(EXIT_FAILURE);
      
   
   /*
    * If no error occurred, the return holds the number of objects
    * scanf() was able to read. We can use this information now.
    * If there is a period (actually any character) after the integer
    * it returns 2 (assuming no error happened, of course)
    */

   /* If no integer given, the following character ("%c") gets ignored. */
   if (scanf_return == 0) 
      fprintf(stderr, "Something went wrong within scanf(): no objects read.\n");
      exit(EXIT_FAILURE);
   
   /* Found two objects, check second one which is the character. */
   if (scanf_return == 2) 
      if (c == '.') 
         fprintf(stderr, "Floating point numbers are not allowed.\n");
         exit(EXIT_FAILURE);
      
   

   if (x <= 1) 
      fprintf(stderr, "Input must be larger than 1!\n");
      exit(EXIT_FAILURE);
   
   printf("The prime factorization of %d is ", x);
   /* No need for that test, x is already larger than one at this point. */
   /* if (x > 1)  */
   while (x%2 == 0) 
      printf("2 ");
      x = x / 2;
   
   for (i = 3; i < 1009; i = i + 2) 
      while (x%i == 0) 
         printf("%d ",i);
         x = x / i;
      
   
   /*  */
   /* Make it pretty. */
   putchar('\n');
   exit(EXIT_SUCCESS);

检查:

$ ./***_003 
Enter an integer:  123
The prime factorization of 123 is 3 41 
$ ./***_003 
Enter an integer:  123.123
Floating point numbers are not allowed.
$ ./***_003 
Enter an integer:  .123
Something went wrong within scanf(): no objects read.

对我来说已经足够好了。有一个小错误:

$ ./***_003 
Enter an integer:  123.
Floating point numbers are not allowed

但我想我可以把它留给亲爱的读者作为练习。

【讨论】:

以上是关于寻找素因数分解的程序的主要内容,如果未能解决你的问题,请参考以下文章

分解素因数

唯一分解定理入门

HDU 4497 GCD and LCM (分解质因数)

数论的一点前置知识

求最小公倍数和最大公约数

Luogu P1075 质因数分解题解