Киш Лорейн [закрыто]

52

Так как это было Pi день в последнее время , я заметил на ряд из проблем , которые просят вас вычислить пи.

Конечно, пирог с заварным кремом Лотарингия - не совсем пирог (вы можете претендовать на бонусный балл +1, если вы угадали вызов из названия). Таким образом, ваша задача - написать алгоритм или метод, который выглядит на первый взгляд как приближенный к Пи, но гарантированно не сходящийся к Пи.

Это закулисная задача, поэтому убедитесь, что она выдаст 3.14 ... для простого теста, например, с 10 итерациями вашего алгоритма. Это также проблема популярности, так что не надо упускать из виду очевидное echo(pi)и сказать, что IEEE 754 с плавающей запятой округляет некоторые цифры вверх или вниз.

Победитель получает Киш Лорин².

¹ Предупреждение: на самом деле не бонусный балл. Заявляя счет, вы соглашаетесь испечь мне пирог до Pi Day, 2016

² Предупреждение: Киш Лорейн используется в качестве метафоры для того, чтобы ваш ответ был помечен как «принятый»

Sanchises
источник
Связанный: ссылка
Sp3000
2
Я голосую, чтобы закрыть этот вопрос как не по теме, потому что закулисные вызовы больше не обсуждаются здесь. meta.codegolf.stackexchange.com/a/8326/20469
кошка

Ответы:

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
Возможно, один из лучших ответов на закулисный вопрос в последнее время.
Оптимизатор
14
"математическая идея практической шутки". +1
unclemeat
16
Этот подходит! IIRC, одна из наиболее известных шуток с этим интегралом была, когда кто-то записал результаты вплоть до странного на Wolfram Alpha и отправил отчет об ошибке ... которую разработчики WA потратили целую вечность, пытаясь исправить =)
Mints97
3
Эта ссылка дает хорошее объяснение того, что происходит.
ТониоЭлГринго
59

Чтобы найти число пи, мы интегрируем это хорошо известное дифференциальное уравнение:

> 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 становится очень большим.

AJMansfield
источник
4
@UriZarfaty Эта статья в Википедии объясняет это довольно хорошо: en.wikipedia.org/wiki/Stiff_equation
AJMansfield
1
Что это n? ...
Коул Джонсон
1
@ AJMansfield Я имел в виду: это нигде не объявлено. Ваше forзамедление использует t, но ваш цикл использует n.
Коул Джонсон
1
@ColeJohnson Я только что исправил это.
AJMansfield
2
Я думаю, что ваше дифференциальное уравнение должно иметь вид dy / dt = sin (y) * exp (t).
Дэвид Чжан
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)приближается к единице, но я не уверен. Как я уже сказал, я случайно наткнулся на это. Я не уверен в его официальном названии. Не пытайтесь сделать это с mслишком маленьким или он будет работать вечно (если 1 + m*m == 1из - за mто , что так мало).

Если кто-нибудь знает название этой последовательности или почему она так себя ведет, я был бы признателен.

soktinpk
источник
Я думаю, что это связано с отменой, которая является потерей цифр при вычитании двух почти равных чисел. S1 и s2 практически равны после итерации.
Санчиз
1
Мне еще предстоит выяснить, как это работает, но это напоминает мне кое о чем, что я когда-то делал: я неоднократно брал кумулятивную сумму шумового сигнала и нормализовал ее до 0, максимальное значение 1. Это сходилось бы к синусоиде, так как это единственный сигнал, который является его собственной антипроизводной (со смещением фазы).
Санчиз
Я спросил это в math.SE, и получил этот ответ.
Sanchises