Я недавно опубликовал один из моих любимых интервью доски вопросов кодирования в„
Code Golf: формула Лейбница для Pi
Ответ 1
J, 14 символов
4*-/%>:+:i.1e6
Объяснение
-
1e6
- номер 1, затем 6 нулей (1000000). -
i.y
генерирует первыеy
не отрицательные числа. -
+:
- это функция, которая удваивает каждый элемент в аргументе списка. -
>:
- это функция, которая увеличивает один элемент в аргументе списка.
Итак, выражение >:+:i.1e6
генерирует первый миллион нечетных чисел:
1 3 5 7...
-
%
- это обратный оператор (числитель "1" можно опустить). -
-/
содержит альтернативную сумму каждого элемента в аргументе списка.
Итак, выражение -/%>:+:i.1e6
генерирует альтернативную сумму обратных чисел первого миллиона нечетных чисел:
1 - 1/3 + 1/5 - 1/7 +...
-
4*
- умножение на четыре. Если вы умножаете на четыре предыдущей суммы, у вас есть π.
Что это! J - мощный язык для математики.
Изменить: сгенерировать 9! (362880) для альтернативной суммы достаточно, чтобы иметь точность в 5 десятичных разрядов, и так как формулу Лейбница можно написать также следующим образом:
4 - 4/3 + 4/5 - 4/7 +...
... вы можете написать более короткую версию 12 символов:
-/4%>:+:i.9!
Ответ 2
Язык: Brainfuck, Char count: 51/59
Считается ли это? =]
Поскольку в Brainfuck нет чисел с плавающей запятой, было довольно сложно заставить деления работать правильно. Grr.
Без символа новой строки (51):
+++++++[>+++++++<-]>++.-----.+++.+++.---.++++.++++.
С новой строкой (59):
+++++++[>+++++++>+<<-]>++.-----.+++.+++.---.++++.++++.>+++.
Ответ 3
Perl
26 символов
26 просто функция, 27 для вычисления, 31 для печати. Из комментариев в этот ответ.
sub _{$-++<1e6&&4/$-++-&_} # just the sub
sub _{$-++<1e6&&4/$-++-&_}_ # compute
sub _{$-++<1e6&&4/$-++-&_}say _ # print
28 символов
28 только вычисление, 34 для печати. Из комментариев. Обратите внимание, что эта версия не может использовать "say".
$.=.5;$\=2/$.++-$\for 1..1e6 # no print
$.=.5;$\=2/$.++-$\for$...1e6;print # do print, with bonus obfuscation
36 символов
36 просто вычисление, 42 для печати. Хадсон берет на себя перестановку трех сторон, из комментариев.
$/++;$\+=8/$//($/+2),$/+=4for$/..1e6
$/++;$\+=8/$//($/+2),$/+=4for$/..1e6;print
Про счет итерации: насколько мои математические воспоминания идут, 400000 достаточно доказуемо, чтобы быть точным до 0,00001. Но миллион (или как минимум 8e5) фактически делает десятичное расширение фактически совпадающим с 5 дробными местами, и это тот же самый символ, поэтому я сохранил это.
Ответ 4
Ruby, 33 символа
(0..1e6).inject{|a,b|2/(0.5-b)-a}
Ответ 5
Другая версия С#:
(60 символов)
4*Enumerable.Range(0, 500000).Sum(x => Math.Pow(-1, x)/(2*x + 1)); // = 3,14159
Ответ 6
52 символа в Python:
print 4*sum(((-1.)**i/(2*i+1)for i in xrange(5**8)))
(51 удаление "x" из xrange.)
36 символов в Octave (или Matlab):
l=0:5^8;disp((-1).^l*(4./(2.*l+1))')
(выполнить "long long", чтобы показать все значимые цифры.) Опуская "disp", мы получаем 30 символов:
octave:5> l=0:5^8;(-1).^l*(4./(2.*l+1))'
ans = 3.14159009359631
Ответ 7
Oracle SQL 73 символа
select -4*sum(power(-1,level)/(level*2-1)) from dual connect by level<1e6
Ответ 8
Язык: C, Char count: 71
float p;main(i){for(i=1;1E6/i>5;i+=2)p-=(i%4-2)*4./i;printf("%g\n",p);}
Язык: C99, Char count: 97 (включая требуемую новую строку)
#include <stdio.h>
float p;int main(){for(int i=1;1E6/i>5;i+=2)p-=(i%4-2)*4./i;printf("%g\n",p);}
Я должен отметить, что вышеупомянутые версии (одинаковые) отслеживают, повлияет ли дополнительная итерация на результат. Таким образом, он выполняет минимальное количество операций. Чтобы добавить дополнительные цифры, замените 1E6
на 1E(num_digits+1)
или 4E5
на 4E(num_digits)
(в зависимости от версии). Для полных программ, возможно, потребуется заменить %g
. float
может потребоваться изменить на double
.
Язык: C, Char count: 67 (см. примечания)
double p,i=1;main(){for(;i<1E6;i+=4)p+=8/i/(i+2);printf("%g\n",p);}
В этой версии используется модифицированная версия опубликованного алгоритма, используемая некоторыми другими ответами. Кроме того, он не так чист и эффективен, как первые два решения, поскольку он заставляет 100 итераций вместо обнаружения, когда итерации становятся бессмысленными.
Язык: C, Char count: 24 (обман)
main(){puts("3.14159");}
Не работает с цифрами > 6.
Ответ 9
Haskell
Я получил его до 34 символов:
foldl subtract 4$map(4/)[3,5..9^6]
Это выражение дает оценку 3.141596416935556.
Изменить: здесь несколько более короткая версия (на 33 символа), которая использует foldl1 вместо foldl:
foldl1 subtract$map(4/)[1,3..9^6]
Отредактируйте 2: 9 ^ 6 вместо 10 ^ 6. Один должен быть экономичным;)
Отредактируйте 3: Замените foldl 'и foldl1' с помощью foldl и foldl1 соответственно. В результате Edit 2 он больше не переполняется. Спасибо ShreevatsaR за это.
Ответ 10
23 символа в MATLAB:
a=1e6;sum(4./(1-a:4:a))
Ответ 11
F #
Попытка # 1:
let pi = 3.14159
Обман? Нет, его победа со стилем!
Попытка № 2:
let pi =
seq { 0 .. 100 }
|> Seq.map (fun x -> float x)
|> Seq.fold (fun x y -> x + (Math.Pow(-1.0, y)/(2.0 * y + 1.0))) 0.0
|> (fun x -> x * 4.0)
Его не настолько компактный, как он мог бы получить, но довольно идиоматический F #.
Ответ 12
общий lisp, 55 символов.
(loop for i from 1 upto 4e5 by 4 sum (/ 8d0 i (+ i 2)))
Ответ 13
Mathematica, 27 символов (возможно, до 26 или выше 33)
NSum[8/i/(i+2),{i,1,9^9,4}]
Если вы удалите исходный "N", тогда он возвращает ответ как (огромную) фракцию.
Если он обманывает, что Mathematica не нуждается в заявлении печати для вывода его результата, добавьте "[email protected]
" для всего 33 символов.
Примечание:
Если он обманывает жестко кодировать количество терминов, то я не думаю, что какой-либо ответ все же получил это право. Проверка, когда текущий срок ниже определенного порога, не лучше, чем hardcoding, количество терминов. Только потому, что текущий термин меняет только 6-ю или 7-ю цифру, это не означает, что сумма достаточных последующих членов не изменит 5-ю цифру.
Ответ 14
Используя формулу для члена ошибки в чередующейся серии (и, следовательно, необходимое количество итераций для достижения желаемой точности не жестко закодировано в программе):
public static void Main(string[] args) {
double tolerance = 0.000001;
double piApproximation = LeibnizPi(tolerance);
Console.WriteLine(piApproximation);
}
private static double LeibnizPi(double tolerance) {
double quarterPiApproximation = 0;
int index = 1;
double term;
int sign = 1;
do {
term = 1.0 / (2 * index - 1);
quarterPiApproximation += ((double)sign) * term;
index++;
sign = -sign;
} while (term > tolerance);
return 4 * quarterPiApproximation;
}
Ответ 15
С#:
public static double Pi()
{
double pi = 0;
double sign = 1;
for (int i = 1; i < 500002; i += 2)
{
pi += sign / i;
sign = -sign;
}
return 4 * pi;
}
Ответ 16
Perl:
$i+=($_&1?4:-4)/($_*2-1)for 1..1e6;print$i
для всего 42 символов.
Ответ 17
Ruby, 41 символ (с использованием irb):
s=0;(3..3e6).step(4){|i|s+=8.0/i/(i-2)};s
Или эта немного более длинная версия non-irb:
s=0;(3..3e6).step(4){|i|s+=8.0/i/(i-2)};p s
Это модифицированный Лейбниц:
- Объединить пары терминов. Это дает вам 2/3 + 2/35 + 2/99 +...
- Pi становится 8 * (1/(1 * 3) + 1/(5 * 7) + 1/(9 * 11) +...)
Ответ 18
F # (Интерактивный режим) (59 символов)
{0.0..1E6}|>Seq.fold(fun a x->a+ -1.**x/(2.*x+1.))0.|>(*)4.
(Устанавливает предупреждение, но пропускает приведения)
Ответ 19
Здесь решение в MUMPS.
pi(N)
N X,I
S X=1 F I=3:4:N-2 S X=X-(1/I)+(1/(I+2))
Q 4*X
Параметр N указывает, сколько повторных фракций использовать. То есть, если вы пройдете в 5, он будет оценивать 4 * (1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11)
Некоторые эмпирические тесты показали, что N = 272241 - это самое низкое значение, которое дает правильное значение 3.14159 при усечении до 5 десятичных знаков. Вы должны пойти в N = 852365, чтобы получить значение, которое округляется до 3.14159.
Ответ 20
JavaScript:
a=0,b=-1,d=-4,c=1e6;while(c--)a+=(d=-d)/(b+=2)
В javascript. 51 символ. Очевидно, что не собираюсь побеждать, но да.: P
Изменить - обновлено до 46 символов, благодаря Strager.:)
ОБНОВЛЕНИЕ (30 марта 2010 г.)
Быстрее (точнее только до 5 знаков после запятой) 43-символьная версия Дэвид Мердок
for(a=0,b=1,d=4,c=~4e5;++c;d=-d)a-=d/(b-=2)
Ответ 21
С# с использованием блока итератора:
static IEnumerable<double> Pi()
{
double i = 4, j = 1, k = 4;
for (;;)
{
yield return k;
k += (i *= -1) / (j += 2);
}
}
Ответ 22
Для записи эта реализация схемы содержит 95 символов, игнорирующих ненужные пробелы.
(define (f)
(define (p a b)
(if (> a b)
0
(+ (/ 1.0 (* a (+ a 2))) (p (+ a 4) b))))
(* 8 (p 1 1e6)))
Ответ 23
Здесь рекурсивный ответ с использованием С#. Он будет работать только с использованием режима x64 JIT в режиме Release, потому что единственная JIT, которая применяет оптимизацию хвостового вызова, и поскольку серия сходится так медленно, это приведет к StackOverflowException
без нее.
Было бы неплохо иметь функцию IteratePi
как анонимную лямбда, но, поскольку она саморекурсивна, нам придется начинать делать всевозможные ужасные вещи с Y-комбинаторами, поэтому я оставил ее как отдельную функция.
public static double CalculatePi()
{
return IteratePi(0.0, 1.0, true);
}
private static double IteratePi(double result, double denom, bool add)
{
var term = 4.0 / denom;
if (term < 0.00001) return result;
var next = add ? result + term : result - term;
return IteratePi(next, denom + 2.0, !add);
}
Ответ 24
Язык: dc, Char count: 35
dc -e '9k0 1[d4r/r2+sar-lad274899>b]dsbxrp'
Ответ 25
Язык: C99 (неявный возврат 0), Char count: 99 (95 + 4 требуемых пробела)
условие выхода зависит от текущего значения, а не от фиксированного счета
#include <stdio.h>
float p, s=4, d=1;
int main(void) {
for (; 4/d > 1E-5; d += 2)
p -= (s = -s) / d;
printf("%g\n", p);
}
компактная версия
#include<stdio.h>
float
p,s=4,d=1;int
main(void){for(;4/d>1E-5;d+=2)p-=(s=-s)/d;printf("%g\n",p);}
Ответ 26
Большинство текущих ответов предполагают, что они получат 5-значную точность в пределах некоторого количества итераций, и это число жестко запрограммировано в программе. Мое понимание вопроса состояло в том, что сама программа должна рассчитывать, когда она получит ответ с точностью до 5 цифр и остановится там. На этом предположении здесь мое решение С#. Я не потрудился свести к минимуму количество персонажей, так как там он не может конкурировать с некоторыми из уже полученных ответов, поэтому я решил, что сделаю это читаемым.:)
private static double GetPi()
{
double acc = 1, sign = -1, lastCheck = 0;
for (double div = 3; ; div += 2, sign *= -1)
{
acc += sign / div;
double currPi = acc * 4;
double currCheck = Math.Round(currPi, 5);
if (currCheck == lastCheck)
return currPi;
lastCheck = currCheck;
}
}
Ответ 27
Ruby:
irb(main):031:0> 4*(1..10000).inject {|s,x| s+(-1)**(x+1)*1.0/(2*x-1)}
=> 3.14149265359003
Ответ 28
С# cheating - 50 символов:
static single Pi(){
return Math.Round(Math.PI, 5));
}
Он говорит только "принимая во внимание формулу, пишущую функцию...", он не говорит, что воспроизводить формулу программно:) Думайте нестандартно...
С# LINQ - 78 символов:
static double pi = 4 * Enumerable.Range(0, 1000000)
.Sum(n => Math.Pow(-1, n) / (2 * n + 1));
С# Альтернативные символы LINQ - 94:
static double pi = return 4 * (from n in Enumerable.Range(0, 1000000)
select Math.Pow(-1, n) / (2 * n + 1)).Sum();
И, наконец, это берет ранее упомянутый алгоритм и конденсирует его математически, поэтому вам не нужно беспокоиться о том, чтобы продолжать менять знаки.
С# longhand - 89 символов (не считая незапрашиваемых пробелов):
static double pi()
{
var t = 0D;
for (int n = 0; n < 1e6; t += Math.Pow(-1, n) / (2 * n + 1), n++) ;
return 4 * t;
}
Ответ 29
64 символа в AWK:
~# awk 'BEGIN {p=1;for(i=3;i<10^6;i+=4){p=p-1/i+1/(i+2)}print p*4}'
3.14159
Ответ 30
#!/usr/bin/env python
from math import *
denom = 1.0
imm = 0.0
sgn = 1
it = 0
for i in xrange(0, int(1e6)):
imm += (sgn*1/denom)
denom += 2
sgn *= -1
print str(4*imm)