C 中的阿姆斯特朗数字程序返回错误的值



我正在编写一个程序来查看用户输入的数字是否是阿姆斯特朗,这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(){
int x = 0;
printf("Enter a natural number: ");
scanf("%d", &x);
int ans = x;
// Digit Counter
int counter = 0;          //Variable for number of digits in the user entered number
int b = x;                //For each time number can be divided by 10 and isnt 0
for (int i = 1; i <= x; i++){ // Then counter variable is incremented by 1
b /= 10;
if (b != 0){
counter += 1;
}            
}
++counter;
//Digit Counter
int sum = 0;
// Digit Finder
int D;
for (int j = 1; j <= x; j++){
D = x % 10;               //Shows remainder of number (last digit) when divided by 10
sum += pow(D, counter);   //Raises Digit found by counter and adds to sum
printf("%dn", sum);
x /= 10;                  // Divides user entered number by 10 to get   rid of digit found
}

if (sum == ans){
printf("%d is a Armstrong number! :)", ans);
}else 
printf("%d is not an Armstrong number :(", ans);
//Digit Finder
return 0;
}

我的问题是,除了一点之外,程序工作正常,当程序被赋予一个不以 1 开头的阿姆斯特朗数时,它的行为正常并指示它是否是阿姆斯特朗数,但是当我输入一个以 1 开头的阿姆斯特朗数时,它将打印出阿姆斯特朗数但-1

例如:如果我输入诸如371之类的东西,这是一个阿姆斯特朗数字,它将显示它是一个阿姆斯特朗数字。但是,如果我输入 1634,它将输出1633,比16341

我该如何解决这个问题?,顺便说一下,有人可以评论我的代码并告诉我它是否看起来不错,专业/高效,因为我是 C 语言的初学者,并希望其他人对我的代码发表意见。

如何解决此问题。

计算出位数后,您就知道要进行的迭代次数。因此,与其循环直到达到x的值:

for (int j = 1; j <= x; j++){

请改用数字counter

for (int j = 1; j <= counter; j++) {

顺便说一下,有人可以评论我的代码并告诉我它是否看起来不错和专业/高效,因为我是 C 语言的初学者,并希望其他人对我的代码发表意见。

你可以做很多事情来改进你的代码。

  1. 首先,任何一段代码都应该正确缩进和格式化。现在你的代码没有缩进,这使得它更难读,而且看起来很丑陋。因此,请始终正确缩进代码。使用IDE或一个好的文本编辑器,它会帮助你。

  2. 代码风格保持一致。如果你在写作

if (some_cond) {
...
}
else
//do this

它并不一致。将其他部分也包裹在大括号中。

  1. 始终检查您使用的函数的返回值,尤其是对于scanf。它将使您将来免于许多错误。

if (scanf("%d", &x) == 1)
//...all OK...
else
// ...EOF or conversion failure...
exit(EXIT_FAILURE);
  1. 你的第一个 for 循环将无用地迭代x次。当您知道自己击中0时,您可以停止:
for (int i = 1; i <= x; i++){ // Then counter variable is incremented by 1
b /= 10;
if (b == 0){
break;
}
counter += 1;    
}
  1. C 有++运算符。使用它而不是做counter += 1

  2. int D;创建它,但不初始化它。始终尽快初始化变量

  3. C 具有const限定符关键字,这使得值不可变。这使您的代码更具可读性,因为读者可以立即知道此值不会更改。在代码中,可以更改变量ans并使其成为const int,因为它永远不会更改:

const int ans = x;
  1. 为变量使用更具描述性的名称。ansD什么都不要告诉我。使用专有名称,以便代码的读者可以轻松理解代码。

在我看来,这些是你应该做并继续做的一些事情,以提高你的代码和编码技能。我相信还可以有更多的事情。保持代码的可读性和尽可能简单。

此循环中的条件

for (int i = 1; i <= x; i++){ // Then counter variable is incremented by 1
b /= 10;
if (b != 0){
counter += 1;
}            
}

没有意义,因为循环将有许多冗余迭代。

例如,如果x等于仅包含3位数字的153,则循环将正好迭代 153 次。

循环后变量计数器的附加增量

++counter;

使代码在逻辑上不一致。

代替循环,您至少可以通过以下方式编写

int counter = 0;
int b = x;
do
{
++counter;
} while ( b /= 10 );

此循环精确地迭代等于给定数字中的位数的次数。

在此循环中

for (int j = 1; j <= x; j++){
D = x % 10;               //Shows remainder of number (last digit) when divided by 10
sum += pow(D, counter);   //Raises Digit found by counter and adds to sum
printf("%dn", sum);
x /= 10;                  // Divides user entered number by 10 to get   rid of digit found
}

您似乎没有考虑到循环主体内部的变量x减少

x /= 10;                  // Divides user entered number by 10 to get   rid of digit found

因此,循环可能会过早中断其迭代。无论如何,循环的条件再次与第一个循环的条件没有多大意义,只会添加一个错误。

存储给定数字的已用变量的类型应为无符号整数类型。否则,用户可以输入负数。

您可以编写一个单独的函数来检查给定的数字是否是阿姆斯特朗数字。

给你。

#include <stdio.h>
int is_armstrong( unsigned int x )
{
const unsigned int Base = 10;

size_t n = 0;
unsigned int tmp = x;
do 
{ 
++n; 
} while ( tmp /= Base );

unsigned int sum = 0;

tmp = x;
do
{
unsigned int digit = tmp % Base;
unsigned int power = digit;

for ( size_t i = 1; i < n; i++ ) power *= digit;

sum += power;
} while ( ( tmp /= Base ) != 0 && !( x < sum ) );

return tmp == 0 && x == sum;
}
int main(void) 
{
unsigned int a[] = 
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 
1634, 8208, 9474, 54748, 92727, 93084, 548834
};
const size_t N = sizeof( a ) / sizeof( *a );

for ( size_t i = 0; i < N; i++ )
{
printf( "%u is %san Armstrong number.n", a[i], is_armstrong( a[i] ) ? "": "not " );
}
return 0;
}

程序输出为

0 is an Armstrong number.
1 is an Armstrong number.
2 is an Armstrong number.
3 is an Armstrong number.
4 is an Armstrong number.
5 is an Armstrong number.
6 is an Armstrong number.
7 is an Armstrong number.
8 is an Armstrong number.
9 is an Armstrong number.
153 is an Armstrong number.
370 is an Armstrong number.
371 is an Armstrong number.
407 is an Armstrong number.
1634 is an Armstrong number.
8208 is an Armstrong number.
9474 is an Armstrong number.
54748 is an Armstrong number.
92727 is an Armstrong number.
93084 is an Armstrong number.
548834 is an Armstrong number.

请从第二个循环for (int j = 1; j <= x; j++)中删除j++

我试过这个:

void armstrong(int x)
{
// count digits
int counter = 0, temp = x, sum = 0;
while(temp != 0)
{
temp = temp/10;
++counter; // Note: pre increment faster
}
// printf("count %dn",counter);

temp = x;
while(temp != 0)
{
sum += pow(temp % 10, counter);
temp = temp/10;
}
// printf("sum %dn",sum);
if(x == sum)
{
printf("Armstrongn");
}
else
{
printf("No Armstrongn");
}
}
int main(){
armstrong(371);
armstrong(1634);
return 0;
}

让我们利用这一点并添加处理多个数字基数的功能。为什么?因为我们罐头!!!:-)

#include <stdio.h>
#include <math.h>
double log_base(int b, double n)
{
return log(n) / log((double)b);
}
int is_armstrong_number(int b,  /* base */
int n)
{
int num_digits = trunc(log_base(b, (double)n)) + 1;
int sum = 0;
int remainder = n;

while(remainder > 0)
{
sum = sum + pow(remainder % b, num_digits);
remainder = (int) (remainder / b);
}
return sum == n;
}
int main()
{
printf("All the following are valid Armstrong numbersn");
printf("  407 base 10 - result = %dn", is_armstrong_number(10, 407));
printf("  0xEA1 base 16 - result = %dn", is_armstrong_number(16, 0xEA1));
printf("  371 base 10 - result = %dn", is_armstrong_number(10, 371));
printf("  1634 base 10 - result = %dn", is_armstrong_number(10, 1634));
printf("  0463 base 8 - result = %dn", is_armstrong_number(8, 0463));

printf("All the following are NOT valid Armstrong numbersn");

printf("  123 base 10 - result = %dn", is_armstrong_number(10, 123));
printf("  0x2446 base 16 - result = %dn", is_armstrong_number(16, 0x2446));
printf("  022222 base 8 - result = %dn", is_armstrong_number(8, 022222));
}

is_armstrong_number开始时,我们直接计算数字数,而不是循环数字。然后,我们遍历以 b 为底的 n 的数字,将数字的值汇总到给定数字基数的数字位数。一旦余数达到零,我们就知道没有更多的数字可以计算,我们返回一个标志,指示给定的数字是否是给定基数中的阿姆斯特朗数。

最新更新