【问题标题】:Wrong answer from spigot algorithmspigot算法的错误答案
【发布时间】:2019-04-05 21:52:30
【问题描述】:

我正在编写用于在 ada 中显示 pi 数字的 spigot 算法,但我的输出是错误的,我不知道为什么

我尝试弄乱我的循环范围和输出数据的不同方式,但没有任何效果

with ada.integer_text_io; use ada.integer_text_io;
with Ada.Text_IO; use Ada.Text_IO;

procedure Spigot is
    n : constant Integer := 1000;
    length : constant Integer := 10*n/3+1;
    x,q,nines,predigit :Integer :=0;
    a: array (0..length) of Integer;

begin
    nines:=0;
    predigit:=0;

    for j in 0..length loop
        a(j):=2;
    end loop;

    for j in  1..n loop
        q:=0;
        for i in reverse 1..length loop
            x:=10*a(i) + q*i;
            a(i):= x mod (2*i-1);
            q:= x/(2*i-1);
        end loop;

        a(1):= q mod 10;
        q:=q/10;

        if q = 9 then
            nines:=nines+1;
        elsif q = 10 then
            put(predigit+1);
            for k in 0..nines loop
                put("0");
            end loop;
            predigit:=0;
            nines:=0;
        else
            put(predigit);
            predigit:=q;
            if nines/=0 then
                for k in 0..nines loop
                    put("9");
                end loop;
                nines:=0;
            end if;      
        end if;   
    end loop;
    put(predigit);
end Spigot;

所以它应该只显示在 0 3 1 4 1 5 9 2 6 5 3 5 8 9... 但我得到的输出是 0 3 1 4 1 599 2 6 5 3 5 89... 它应该一次只能是 1 位,而且 pi 的输出值也不完全正确

【问题讨论】:

    标签: ada pi spigot-algorithm


    【解决方案1】:

    我不太了解算法,无法谈论为什么数字不正确,但我确实注意到了一些问题:

    1. 您的数组定义为边界 0 .. 长度,这将为您提供 1 个额外元素
    2. 在进行计算的循环中,您从 1..length 开始循环,这没问题,但您不会始终如一地调整变量 i。数组索引需要比实际计算中使用的 i 小一(请记住,它们仍然必须正确地位于数组的范围内)。例如

          x:=10*a(i) + q*i;
      

      必须是

          x:=10*a(i-1) + q*i;
      

          x:=10*a(i) + q*(i+1);
      

      取决于你决定你的数组边界是什么。这适用于代码中的多行。看到这个Stackoverflow thread

    3. 当数组从 0 开始时分配 A(1)

    4. 打印“0”和“9”的循环应该是 1..length 或 0..length-1
    5. 使用 Integer_Text_IO.Put 打印数字时,需要指定宽度 1 以消除空格

    可能还有更多,这就是我所看到的。

    【讨论】:

      【解决方案2】:

      我想你是在翻译this answer

      您需要更加小心您的索引和循环范围;例如,您已经翻译了

      for(int i = len; i > 0; --i) {
        int x  = 10 * A[i-1] + q*i;
        A[i-1] = x % (2*i - 1);
        q = x / (2*i - 1);
      }
      

      作为

      for i in reverse 1..length loop
          x:=10*a(i) + q*i;
          a(i):= x mod (2*i-1);
          q:= x/(2*i-1);
      end loop;
      

      循环范围相同。但是在 seocnd 行中,C 代码使用A[i-1],而您的使用a(i);第三行类似。

      稍后,对于

        for (int k = 0; k < nines; ++k) {
          printf("%d", 0);
        }
      

      你有

        for k in 0..nines loop
            put("0");
        end loop;
      

      其中 C 循环从 0 运行到 nines - 1,但您的循环从 0 运行到 nines。所以你多发了一个0(后来,9s 也是如此)。

      另外,你应该使用put (predigit, width=&gt; 0)

      【讨论】:

      • 您能否详细说明我有点困惑,对于您给出的第一个示例,我认为它的翻译正确,范围的差异是因为我超出了边界错误,与第二个相同例如,但看起来我的一般流程是正确的,除非我错过了什么
      • 我在发布我的答案后才看到你的答案。我应该删除我的吗?我们涵盖的内容基本相同。
      • @Jere,我想我应该删除我的,因为你的显然更有帮助!只要说出这个词...
      • @SimonWright Nah,我只是想确保我没有违反 SO 协议或粗鲁。我不想狙击别人的答案。我会说让你的完好无损。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-12
      • 2019-02-19
      • 1970-01-01
      • 1970-01-01
      • 2014-11-07
      • 2017-04-29
      • 1970-01-01
      相关资源
      最近更新 更多