简单的C问题

我不得不开始学习C作为我正在做的项目的一部分。 我已经开始在其中处理’euler’问题并且遇到第一个问题 。 我必须找到1000或以下3或5的所有倍数的总和。有人可以帮助我。 谢谢。

#include int start; int sum; int main() { while (start < 1001) { if (start % 3 == 0) { sum = sum + start; start += 1; } else { start += 1; } if (start % 5 == 0) { sum = sum + start; start += 1; } else { start += 1; } printf("%d\n", sum); } return(0); } 

到目前为止,你已经得到了一些很好的答案,主要是建议:

 #include  int main(int argc, char * argv[]) { int i; int soln = 0; for (i = 1; i < 1000; i++) { if ((i % 3 == 0) || (i % 5 == 0)) { soln += i; } } printf("%d\n", soln); return 0; } 

所以我要采取不同的策略。 我知道你这样做是为了学习C,所以这可能有点切线。

真的,你让计算机的工作太难了:)。 如果我们提前想出一些事情,它可以使任务更容易。

那么,有多少3的倍数小于1000? 每次有3个进入1000 - 1。

mult 3 =⌊(1000 - 1)/ 3⌋= 333

(⌊和⌋表示这是底线划分,或者,在编程术语中, 整数除法,其余部分被删除)。

有多少5的倍数小于1000?

mult 5 =⌊(1000 - 1)/ 5⌋= 199

现在所有3的倍数小于1000的总和是多少?

3 = 3 + 6 + 9 + ... + 996 + 999 = 3×(1 + 2 + 3 + ... + 332 + 333)= 3×Σi = 1到mult 3 i

并且所有5的倍数的总和小于1000?

5 = 5 + 10 + 15 + ... + 990 + 995 = 5×(1 + 2 + 3 + ... + 198 + 199)= 5×Σi = 1到mult 5 i

3的倍数也是5的倍数。这些是15的倍数。因为那些计数为mult 3和mult 5 (因此总和35 )我们需要知道mult 15和sum 15以避免计算它们两次。

mult 15 =⌊(1000 - 1)/ 15⌋= 66

15 = 15 + 30 + 45 + ... + 975 + 990 = 15×(1 + 2 + 3 + ... + 65 + 66)= 15×Σi = 1到mult 15 i

因此,问题的解决方案是“ 找到所有3或5的倍数的总和低于1000 ”

soln = sum 3 + sum 5 - sum 15

所以,如果我们想,我们可以直接实现:

 #include  int main(int argc, char * argv[]) { int i; int const mult3 = (1000 - 1) / 3; int const mult5 = (1000 - 1) / 5; int const mult15 = (1000 - 1) / 15; int sum3 = 0; int sum5 = 0; int sum15 = 0; int soln; for (i = 1; i <= mult3; i++) { sum3 += 3*i; } for (i = 1; i <= mult5; i++) { sum5 += 5*i; } for (i = 1; i <= mult15; i++) { sum15 += 15*i; } soln = sum3 + sum5 - sum15; printf("%d\n", soln); return 0; } 

但我们可以做得更好。 为了计算各个和,我们有高斯的同一性 ,它表示从1到n的总和(又名Σi = 1到n i)是n×(n + 1)/ 2,所以:

3 = 3×mult 3 ×(mult 3 +1)/ 2

5 = 5×mult 5 ×(mult 5 +1)/ 2

15 = 15×mult 15 ×(mult 15 +1)/ 2

(注意,我们可以在这里使用正常除法或整数除法 - 因为n或n + 1中的一个必须可被2整除,所以无关紧要)

现在这有点整洁,因为这意味着我们可以在不使用循环的情况下找到解决方案:

 #include  int main(int argc, char *argv[]) { int const mult3 = (1000 - 1) / 3; int const mult5 = (1000 - 1) / 5; int const mult15 = (1000 - 1) / 15; int const sum3 = (3 * mult3 * (mult3 + 1)) / 2; int const sum5 = (5 * mult5 * (mult5 + 1)) / 2; int const sum15 = (15 * mult15 * (mult15 + 1)) / 2; int const soln = sum3 + sum5 - sum15; printf("%d\n", soln); return 0; } 

当然,既然我们已经走了这么远,我们可以手工制作出整个东西:

3 = 3×333×(333 + 1)/ 2 = 999×334/2 = 999×117 = 117000 - 117 = 116883

5 = 5×199×(199 + 1)/ 2 = 995×200/2 = 995×100 = 99500

15 = 15×66×(66 + 1)/ 2 = 990×67/2 = 495×67 = 33165

soln = 116883 + 99500 - 33165 = 233168

并编写一个更简单的程序:

 #include  int main(int argc, char *argv[]) { printf("233168\n"); return 0; } 

你可以改变你的ifs:

  if ((start % 3 == 0) || (start % 5 == 0)) sum += start; start ++; 

并且不要忘记用零初始化你的总和并从一开始。 另外,将while条件更改为<1000。

你可以通过for循环更好地服务,并结合你的条件。

未经测试:

 int main() { int x; int sum = 0; for (x = 1; x <= 1000; x++) if (x % 3 == 0 || x % 5 == 0) sum += x; printf("%d\n", sum); return 0; } 

答案都很好,但不会帮助你学习C.

您真正需要了解的是如何找到自己的错误。 调试器可以帮助您,C中最强大的调试器称为“printf”。 你想知道你的程序在做什么,你的程序不是一个“黑匣子”。

你的程序已打印出总和,这可能是错误的,你想知道原因。 例如:

 printf("sum:%d start:%d\n", sum, start); 

代替

 printf("%d\n", sum); 

并将其保存到文本文件中,然后尝试了解出现了什么问题。

  • 计数从1开始到999结束吗?
  • 它是否真的从1到999没有跳过数字?
  • 它适用于较小的范围吗?

呃,我可以大致看到你要去的地方,我想以前唯一有问题的就是前面提到的。 我之前做过这个问题,显然你需要逐步完成3和5的每个倍数并总结它们。 我这样做了它确实有效:

 int accumulator = 0; int i; for (i = 0; i < 1000; i += 3) accumulator += i; for (i = 0; i < 1000; i +=5) { if (!(i%3==0)) { accumulator += i; } } printf("%d", accumulator); 

编辑:还要注意它不是0到1000,包括<1000停止在999,因为它是1000以下的最后一个数字,你已经反对<1001这意味着你一直到1000这是5的倍数意味着你的答案将比它应该高1000。

你没有说过程序应该做什么,或者你的问题是什么。 这使得很难提供帮助。

猜测,你真的应该初始化start和sum为零,也许printf应该在循环之外。

真的,你需要一个调试器,并单步执行代码,以便你可以看到它实际上在做什么。 你的基本问题是控制流不是你想象的那样,而不是像其他人那样提供正确的代码,我会试着解释你的代码做了什么。 这是发生的事情,一步一步(我已经对行编号):

 1: while (start < 1001) { 2: if (start % 3 == 0) { 3: sum = sum + start; 4: start += 1; 5: } 6: else { 7: start += 1; 8: } 9: 10: if (start % 5 == 0) { 11: sum = sum + start; 12: start += 1; 13: } 14: else { 15: start += 1; 16: } 17: printf("%d\n", sum); 18: } 
  • line 1. sum为0,start为0.循环条件为true。
  • 第2行。和为0,开始为0.如果条件为真。
  • 第3行。和为0,start为0. sum < - 0。
  • 第4行。和为0,开始为0.开始< - 1。
  • 第5行。总和为0,开始为1.跳过“else”子句
  • 第10行。和为0,开始为1.如果条件为false,则跳转到“else”子句。
  • 第15行。总和为0,开始为1.开始< - 2。
  • 第16行(跳过)
  • 第17行。和为0,开始为2.打印“0 \ n”。
  • 第18行.sum为0,start为2.跳转到循环顶部。
  • line 1. sum为0,start为2.循环条件为true。
  • 第2行。总和为0,启动为2.如果condtion为false,则跳转到“else”子句。
  • 第7行。总和为0,开始为2.开始< - 3。
  • 第10行。和为0,开始为3.如果条件为false,则跳转到“else”子句。
  • 第15行。和为0,开始为3.开始< - 4。
  • 第17行。和为0,开始为4.打印“0 \ n”。

你看这是怎么回事? 您似乎认为在第4行,在执行sum += 1 ,控制返回到循环的顶部。 它不会,它会在“if / else”构造之后进行下一步。

您忘记初始化变量,

代码的问题在于你将’start’变量递增两次。 这是因为有两个if..else语句。 你需要的是if..else if..else语句如下:

  if (start % 3 == 0) { sum = sum + start; start += 1; } else if (start % 5 == 0) { sum = sum + start; start += 1; } else { start += 1; } 

或者您可以更简洁,并按如下方式编写:

 if(start % 3 == 0) sum += start; else if(start % 5 == 0) sum += start; start++; 

这两种方式中的任何一种都应该适合你。

祝好运!

这是一个适用于任意数量因素的通用解决方案:

 #include  #define sum_multiples(BOUND, ...) \ _sum_multiples(BOUND, (unsigned []){ __VA_ARGS__, 0 }) static inline unsigned sum_single(unsigned bound, unsigned base) { unsigned n = bound / base; return base * (n * (n + 1)) / 2; } unsigned _sum_multiples(unsigned bound, unsigned bases[]) { unsigned sum = 0; for(unsigned i = 0; bases[i]; ++i) { sum += sum_single(bound, bases[i]); for(unsigned j = i + 1; bases[j]; ++j) sum -= sum_single(bound, bases[i] * bases[j]); } return sum; } int main(void) { printf("%u\n", sum_multiples(999, 3, 5)); return 0; }