【问题标题】:Estimate PI with series expansion using loops使用循环通过级数展开来估计 PI
【发布时间】:2017-10-07 21:36:44
【问题描述】:

我需要通过以下系列来估算 PI:

m(i) = 4( 1- 1/3 + 1/5 - 1/7 + 1/9 - 1/11 ...)

这就是我到目前为止所做的:

 float mOfI = 1;
    System.out.println("i \t \t \t \t  m(i)" );
    for (int i = 1; i < n; i++) {
        float sum = i + 2;
        mOfI += 4 * (1 - (1 / sum));
        mOfI -= 4 * (1 - (1 / sum));
        System.out.println(i + "\t \t \t \t" +mOfI);
    }

我知道我在这里遗漏了许多规则,但我怎样才能使它正常工作?我的意思是数学逻辑。怎样才能正确解决?

请注意系列中的-+,所有数字都是奇数,所以我不能使用i%2

估计的 PI 会像 4.0000 , 3.1515, 3.1466 ..... 等等。

这个question 也没有得到很好的回答(没有估计实际的 PI 值)

【问题讨论】:

  • 问题出在哪里?为什么它不起作用?请突出显示。
  • @Zabuza 因为它没有正确地完成系列。
  • 是的,很明显。它目前制作的系列是什么?如果您强调这一点,您将更快地获得帮助。
  • 首先,使用 BigInteger 来实现这种精度。
  • @Zabuza 不,不对,你提到的问题并没有给出正确的 PI 值,顺便说一句,我在下面的回答中解决了它,谢谢。

标签: java algorithm loops for-loop pi


【解决方案1】:

让它变得简单,找到简单的模式。这是一个提示

  1. 先忽略与4的乘法(或者你可以考虑 每个学期)
  2. 考虑初始 denom = 1,因此 term = 1/denom = 1
  3. 找到模式。请注意,在每一步 newTerm = (-1)*(1/(denom+2))。所以在每次迭代中,更新总和和 denom 相应地。
  4. n 次迭代后,只需将 sum 与 4 相乘

【讨论】:

  • 同一系列不同的-+呢?
【解决方案2】:

mOfI 永远不会改变,因为这两行相互抵消

    mOfI += 4 * (1 - (1 / sum));
    mOfI -= 4 * (1 - (1 / sum));

试试这个。

double mOfI = 4.0;
System.out.println("i \t \t \t \t  m(i)" );
for (int i = 1, d = 3, s = -1;
         i < n; 
         i++, d += 2, s = -s) {
    mOfI += 4.0 / (s * d);
    System.out.println(i + "\t \t \t \t" +mOfI);
}

【讨论】:

  • 您能解释一下为什么您的代码可以解决问题吗?它看起来也很复杂,尤其是对于初学者。
【解决方案3】:
float m = 4;
    for (int i = 1; i < n; i++) {
        if(i%2==0){
           m +=4/(2*i+1);
        } else {
           m -=4/(2*i+1);
        }
        System.out.println(i + "\t \t \t \t" +m);
    }

注意:我使用的是移动应用程序,可能存在语法错误,但您应该明白。

【讨论】:

  • 你看过这个系列吗?都是奇数,确实会有一个条件
  • 你运行代码了吗?它给出了 Gregory-Leibniz 系列。
  • 我很想知道投反对票的原因。
  • 还请给出解释,而不仅仅是代码。特别是对于初学者来说,这将更有帮助。至少这可能是投票的原因。
【解决方案4】:

感谢大家的宝贵时间,但我找到了正确的解决方案:

  double start = 1;         // Start series
    double end   = 901;     // End series
    System.out.println("\ni           m(i)     ");
    System.out.println("---------------------");
    for (double i = start; i <= end; i += 100) {
        System.out.printf("%-12.0f", i);
        System.out.printf("%-6.4f\n", estimatePI(i));
    }
}

/** Method estimatePI */
public static double estimatePI(double n) {
    double pi = 0;      // Set pi to 0
    for (double i = 1; i <= n; i ++) {
        pi += Math.pow(-1, i +1) / (2 * i - 1);
    }
    pi *= 4;
    return pi;
}

【讨论】:

    【解决方案5】:

    您的代码中存在多个问题。

    1. 首先,您应该只将一个和除以i,将另一个除以i + 2,而不是同时除以i + 2
    2. 你将1添加到每个summand,这是错误的,它应该像1 / sum而不是1 - (1 / sum)
    3. 接下来i 需要在每个步骤中进一步推进,i+2 甚至 i+4 如果您决定在一个迭代步骤中创建两个加法运算
    4. 如果n 变大,您可能会很快达到intdouble 精度的极限,您可能需要BigIntegerBigDecimal,它们在空间成本上提供无限精度 .

    您目前正在制作的系列看起来像:

    4 * ((1 - 1 / 1) - (1 - 1 / 1) + (1 - 1 / 2) - (1 - 1 / 2) +- ...)
    

    应该是0,因为每个部分相互消除。


    正确的版本如下所示:

    double result = 0;
    
    // Whether we add or subtract the summand
    boolean doAdd = true;
    // Start at i = 0 to produce 1 as first denominator,
    // else use - instead of + in the code
    for (int i = 0; i < n; i++) {
        // Advance in steps of 2 and use odd values
        // Denominator will be 1, 3, 5, 7, ... for i = 0, 1, 2, 3, ...
        double summand = 1 / (2 * i + 1);
    
        if (doAdd) {
            // Add it
            result += summand;
        } else {
            // Subtract it
            result -= summand;
        }
        // Toggle the flag
        doAdd = !doAdd;
    }
    
    // Multiply by 4
    result *= 4;
    

    当然,如前所述,您可能需要替换为BigDecimal

    如果您不想使用额外的标志,也可以使用if (i % 2 == 0) 代替if (doAdd)。但这样可能更容易理解。

    【讨论】:

    • 谢谢,这个doAdd != doAdd 是合法的语法吗?
    • 这是合法的语法。它切换boolean 的状态。例如,如果它的当前值为true,它将是:doAdd = !true,即false。如果它目前是false,它将是doAdd = !false,即true
    • 哦,对不起,我的意思当然是doAdd = !doAdd;,我更正了。
    【解决方案6】:

    这只是函数式编程中的 Java 9 练习;你可以用这条线计算 PI:

    double pi = 4 * Stream.iterate(1.0, i -> i < 10000000, i -> i + 2)
                .reduce(0.0, (a, d) -> ((d - 1) / 2) % 2 == 0 ? (a + 1 / d) : (a - 1 / d));
    

    Java 8 和 Java 9 示例:

    // Java 9
    double pi = 4 * Stream.iterate(1.0, i -> i < 10000000, i -> i + 2)
            .reduce(0.0, (a, d) -> ((d - 1) / 2) % 2 == 0 ? (a + 1 / d) : (a - 1 / d));
    System.out.println(pi);
    // Java 8
    pi = 4 * Stream.iterate(1.0, i -> i + 2).limit(10000000)
            .reduce(0.0, (a, d) -> ((d - 1) / 2) % 2 == 0 ? (a + 1 / d) : (a - 1 / d));
    System.out.println(pi);
    

    【讨论】:

    • 我正在使用 java 8
    • 我还添加了一个 Java 8 示例。这只是为了证明您可以在 Java 中使用函数式样式做同样的事情。当然还有其他方法可以完成相同的任务。
    猜你喜欢
    • 2019-08-10
    • 1970-01-01
    • 1970-01-01
    • 2019-08-17
    • 2014-12-14
    • 1970-01-01
    • 2015-05-15
    • 2012-02-17
    • 1970-01-01
    相关资源
    最近更新 更多