乳蛋饼洛林[关闭]


52

由于这是丕日最近,我注意到一个挑战,询问您是否计算圆周率。

当然,洛林蛋饼也不是一个好蛋(如果您猜对了挑战,就可以申请+1的奖励分数¹)。因此,你的任务是写一个算法方法看起来像它的第一眼近似于皮,但保证不会收敛朝皮。

这是一个不足的挑战,因此请确保针对简单的测试用例(例如,使用10次算法迭代)将输出3.14...。这也是一个普及性挑战,因此请不要echo(pi)直言不讳地说IEEE 754浮点向上或向下舍入一些数字。

优胜者得到洛林蛋饼。

¹警告:实际上不是奖金分数。索取分数,即表示您同意在2016年Pi Day之前给我烤馅饼

² 警告:洛林乳蛋饼被用作隐喻,将您的答案标记为“已接受”



2
我投票结束这个问题是题外话,因为在这里不再面临挑战。meta.codegolf.stackexchange.com/a/8326/20469

Answers:


77

算法

使用众所周知的结果:

在此处输入图片说明

我们在Python 3中定义:

from math import sin
from functools import reduce
from operator import mul

def integrate(f, a, b, n):
   h = (b-a)/n
   i = h * sum(f(a+i*h+h/2) for i in range(n))
   return i

def sinc(x):
   return sin(x)/x

def borwein(n):
   def f(x):
     g = lambda i: sinc(x/(2*i+1))
     return reduce(mul, map(g, range(n)), 1)
   return f

测试中

>>> for i in range(1,10):
...   pi = 2 * integrate(borwein(i), 0, 1000, 1000)
...   print("x[{}] = {}".format(i, pi))
x[1] = 3.140418050361841
x[2] = 3.141593078648859
x[3] = 3.1415926534611547
x[4] = 3.1415926535957164
x[5] = 3.1415926535895786
x[6] = 3.1415926535897953
x[7] = 3.1415926535897936
x[8] = 3.1415926535435896 # ???
x[9] = 3.141592616140805  # ?!!

扰流板

Borwein积分是恶作剧的数学的想法。虽然上面的标识保持为sinc(x / 13),但下一个值实际上是:

在此处输入图片说明


12
可能是最近有人对这个问题最好的答案之一。
Optimizer

14
“数学上的恶作剧想法”。+1
轻松击败2015年

16
那是一个好人!IIRC,这个积分最著名的笑话之一是,有人在Wolfram Alpha上记录了直到奇怪的结果,并发送了错误报告... WA开发人员花了
很长时间

3
该参考资料很好地解释了正在发生的事情。
TonioElGringo 2015年

59

为了找到pi,我们将整合这个众所周知的微分方程:

> dy / dt = sin(y)* exp(t)

有初始条件

> 0 <y0 <2 *圆周率

众所周知,随着t的增加,该初值问题收敛到π。因此,我们所需要做的就是从0到2π之间的合理猜测开始,然后执行数值积分。3接近π,所以我们选择y = 3开始。

class PiEstimator {

    static final int numSteps = 100;
    static final double dt = 0.1, tMax = numSteps * dt;

    static double f(double y, double t){ return Math.sin(y) * Math.exp(t); }

    public static void main(String[] args){
        double y = 3;
        int n = 0;

        for(double t = 0; t < tMax; t+=dt){
            if(n%5 == 0) System.out.println(n + ": " + y);
            n++;
            y += f(y,t)*dt;
        }
    }
}

以下是每个步骤数不同的一些结果:

0: 3.0
5: 3.0682513992369205
10: 3.11812938865782
15: 3.1385875952782825
20: 3.141543061526081
25: 3.141592653650948
30: 3.1415926535886047
35: 3.1415926535970526
40: 3.1415926517316737  // getting pretty close!
45: 3.1416034165087647  // uh oh
50: 2.0754887983317625  
55: 49.866227663669584
60: 64.66835482328707
65: 57.249212987256286
70: 9.980977494635624
75: 35.43035516640032
80: 51.984982646834
85: 503.8854575676292
90: 1901.3240821223753
95: 334.1514462091029
100: -1872.5333656701248

这个怎么运作:

该微分方程是众所周知的,因为很难正确积分。尽管对于较小的t值,幼稚的积分将产生可接受的结果,但是大多数积分方法在t变得很大时表现出极大的不稳定性。


4
@UriZarfaty这篇Wikipedia文章对其进行了很好的解释:en.wikipedia.org/wiki/Stiff_equation
AJMansfield,2015年

1
什么是n?...
科尔·约翰逊

1
@AJMansfield我的意思是:它没有在任何地方声明。你for减速使用t,但你的循环使用n
科尔·约翰逊

1
@ColeJohnson我刚刚修复了它。
AJMansfield'3

2
我认为您的微分方程应为dy / dt = sin(y)* exp(t)。
David Zhang

6

码:

var pi = function(m) {
  var s2 = 1, s1 = 1, s = 1;
  for (var i = 0; s >= 0; ++i) {
    s = s1 * 2 - s2 * (1 + m*m);
    s2 = s1;
    s1 = s;
  }
  return i*m*2;
};

我基本上是偶然发现了这个序列。它始于,1, 1之后的每个术语s(n)均由给出s(n) = 2*s(n - 1) - s(n - 2) * (1 + m*m)。最终结果是最小的n,从而s(n) < 0乘以2m。随着m变小,它应该变得越来越准确。

pi(1/100) --> 3.14
pi(1/1000) --> 3.14
pi(1/10000) --> 3.1414
pi(1/100000) --> 3.14158
pi(1/1000000) --> 3.141452 // what?
pi(1/10000000) --> 3.1426524 // .. further away from pi

我很确定这些浮点错误(1 + m*m)接近1,但是我不确定。就像我说的那样,我偶然发现了这个。我不确定它的正式名称。不要将其尝试m太小,否则它将永远运行(如果1 + m*m == 1由于m太小而导致)。

如果有人知道该序列的名称或为什么它如此显示,我将不胜感激。


我认为这是由于取消,这是在减去两个几乎相等的数字时的数字损失。迭代后,S1和s2几乎相等。
桑契斯2015年

1
我还没有找到它是如何工作的,但是这让我想起了我曾经做过的事情:我反复获取一个噪声信号的累积和,并将其归一化为0,最大值1。这会收敛为一个正弦波,因为那是唯一的信号,它是它自己的反导数(具有相位偏移)。
桑契斯,2015年

我在math.SE上提出了问题,并得到了这个答案。
桑契斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.