代码之家  ›  专栏  ›  技术社区  ›  marc lincoln

简单C问题

c
  •  3
  • marc lincoln  · 技术社区  · 15 年前

    作为我正在做的项目的一部分,我必须开始学习C。我已经开始在其中处理“euler”问题,并且在 first one . 我必须找出1000以下所有3或5的倍数之和。有人能帮我吗?谢谢。

    #include<stdio.h>
    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);
    }
    
    10 回复  |  直到 6 年前
        1
  •  50
  •   rampion    15 年前

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

    #include <stdio.h>
    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,就有一个。

    穆尔特 =(1000-1)/3=333

    (这和表示 地板 部门,或者,在编程术语中, 整数 除法,删除余数)。

    5的倍数有多少小于1000?

    穆尔特 =(1000-1)/5=199

    现在3的所有倍数加起来是多少,小于1000?

    总和 =3+6+9+…+996+999=3×(1+2+3+……+332+333)=3×∑ i=1

    5的所有倍数之和小于1000?

    总和 =5+10+15+…+990+995=5×(1+2+3+……+198+199)=5×∑ i=1

    有些3的倍数也是5的倍数。这是15的倍数。 因为这些都算在穆特身上 和多 (因此,总和 和和 )我们需要了解穆特 十五 和和 十五 避免数到两次。

    穆尔特 十五 =(1000-1)/15=66

    总和 十五 =15+30+45+…+975+990=15×(1+2+3+……+65+66)=15×∑ i=1 十五

    所以问题的解决办法” find the sum of all the multiples of 3 or 5 below 1000 “那时

    索恩=求和 +和 十五

    因此,如果我们愿意,我们可以直接实现这一点:

    #include <stdio.h>
    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;
    }
    

    但我们可以做得更好。为了计算单个的和,我们有 Gauss's identity 表示从1到n的总和(即∑ i=1到n i)是n×(n+1)/2,所以:

    总和 =3×多 ×(多) + 1)/ 2

    总和 =5×多 ×(多) + 1)/ 2

    总和 十五 =15×多 十五 ×(多) 十五 + 1)/ 2

    (请注意,我们可以在这里使用正除法或整数除法-这并不重要,因为n或n+1中的一个必须被2整除)

    现在这是一种简洁的方法,因为它意味着我们可以在不使用循环的情况下找到解决方案:

    #include <stdio.h>
    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×333×(333+1)/2=999×334/2=999×117=117000-117=116883

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

    总和 十五 =15×66×(66+1)/2=990×67/2=495×67=33165

    索伦=116883+99500-33165=233168

    写一个更简单的程序:

    #include <stdio.h>
    int main(int argc, char *argv[])
    {
      printf("233168\n");
      return 0;
    }
    
        2
  •  17
  •   Fabio Vinicius Binder    15 年前

    你可以改变你的假设:

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

    别忘了用零初始化和,从一开始。 另外,将while条件更改为<1000。

        3
  •  6
  •   anthony    15 年前

    您最好使用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;
    }
    
        4
  •  3
  •   G B    15 年前

    答案都很好,但对你学习C没有帮助。

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

    你的程序已经打印了总数,可能是错误的,你想知道为什么。例如:

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

    而不是

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

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

    • 计数从1开始到999结束吗?
    • 它真的从1到999而不跳过数字吗?
    • 它在较小的范围内工作吗?
        5
  •  3
  •   Toby    15 年前

    嗯,好吧,我大致可以看出你要去哪里,我想这件事唯一的问题是之前提到过的。我以前在那里做过这个问题,很明显你需要单步处理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(包括0到1000),1000停在999,因为它是1000以下的最后一个数字,您已经用<1001来反驳它,这意味着您一直走到1000,这是5的倍数,意味着您的答案将比它应该的高1000。

        6
  •  2
  •   KeyserSoze    15 年前

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

    估计,您真的应该将start和sum初始化为零,也许printf应该在循环之外。

        7
  •  2
  •   Steve Jessop    15 年前

    实际上,您需要一个调试器,只需单步执行代码,就可以看到它实际在做什么。您的基本问题是,控制流不会按您认为的方向发展,我将尝试解释您的代码的作用,而不是像其他人那样提供正确的代码。以下是发生的事情,一步一步(我已经编号了行):

    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:    }
    
    • 第1行。sum为0,start为0。循环条件为真。
    • 第2行。sum为0,start为0。如果条件为真。
    • 第3行。sum为0,start为0。总和<0。
    • 第4行。sum为0,start为0。开始& lt;- 1。
    • 第5行。总和为0,起始值为1。跳过“else”条款
    • 第10行。总和为0,起始值为1。如果条件为假,则跳到“else”子句。
    • 第15行。总和为0,起始值为1。开始& lt;- 2。
    • 第16行(跳过)
    • 第17行。总和为0,起始值为2。打印“0 \n”。
    • 第18行。总和为0,起始值为2。跳到循环的顶部。
    • 第1行。总和为0,起始值为2。循环条件为真。
    • 第2行。总和为0,起始值为2。如果条件错误,跳到“else”子句。
    • 第7行。总和为0,起始值为2。开始& lt;- 3。
    • 第10行。总和为0,起始值为3。如果条件为假,则跳到“else”子句。
    • 第15行。总和为0,起始值为3。开始& lt;- 4。
    • 第17行。总和为0,起始值为4。打印“0 \n”。

    你看到了吗?你好像觉得在第四行 sum += 1 ,控件返回到循环的顶部。它没有,它在“if/else”构造之后进入下一个步骤。

        8
  •  2
  •   Christy John    15 年前

    你忘了初始化变量,

        9
  •  1
  •   foobarfuzzbizz    15 年前

    您的代码的问题是您将“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++;
    

    这两种方法中的任何一种都适合你。

    祝你好运!

        10
  •  0
  •   Christoph    15 年前

    下面是一个通用的解决方案,它可以处理任意数量的因素:

    #include <stdio.h>
    
    #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;
    }