Совместность и число пи


23

Введение

Теория чисел полна чудес в виде неожиданных связей. Вот один из них.

Два целых числа является со-премьером , если они не имеют общие моменты, кроме 1. Дан число N , рассмотрят все целые числа от 1 до N . Нарисуйте два таких целых числа случайным образом (все целые числа имеют одинаковую вероятность быть выбранными при каждом розыгрыше; розыгрыши являются независимыми и с заменой). Пусть p обозначает вероятность того, что два выбранных целых числа взаимно просты. Тогда p стремится к 6 / π 2 ≈ 0,6079 ... как N стремится к бесконечности.

Соревнование

Цель этой задачи состоит в вычислении р как функция от N .

В качестве примера рассмотрим N = 4. Есть 16 возможных пар, полученных из целых чисел 1,2,3,4. 11 из этих пар взаимно просты, а именно (1,1), (1,2), (1,3), (1,4), (2,1), (3,1), (4,1 ), (2,3), (3,2), (3,4), (4,3). Таким образом, р = 11/16 = 0,6875 для N = 4.

Точное значение р должно быть вычислено по меньшей мере , четырех знаков после запятой. Это подразумевает, что вычисления должны быть детерминированными (в отличие от Монте-Карло). Но это не должно быть прямым перечислением всех пар, как указано выше; любой метод может быть использован.

Можно использовать аргументы функции или stdin / stdout. Если отображается вывод, конечные нули могут быть опущены. Так, например, 0.6300может отображаться как 0.63. Он должен отображаться в виде десятичного числа, а не в виде дроби (отображение строки 63/100не допускается).

Критерий выигрыша - наименьшее количество байтов. Нет никаких ограничений на использование встроенных функций.

Контрольные примеры

Ввод / вывод (только четыре знака после запятой обязательны, как указано выше):

1    / 1.000000000000000
2    / 0.750000000000000
4    / 0.687500000000000
10   / 0.630000000000000
100  / 0.608700000000000
1000 / 0.608383000000000

Есть ли границы диапазона входов?
Эрик Тауэрс

@EricTowers Программа должна работать для любого разумного размера, вплоть до ограничений памяти и типа данных. По крайней мере 1000
Луис Мендо

Разрешены ли рациональные числа как возвращаемые значения (не строки)? Мой язык имеет собственный рациональный тип, в котором 63/100допустимый литерал, пригодный для вычислений. (Langs, о котором я говорю: Factor , Racket )
кошка

@ Cat Конечно, давай! Примите во внимание требуемую точность, хотя
Луис Мендо

Ответы:


14

Желе , 12 8 байт

RÆṪSḤ’÷²

Попробуйте онлайн!

Следующий двоичный код работает с этой версией интерпретатора Jelly .

0000000: 52 91 b0 53 aa b7 9a 8a  R..S....

идея

Ясно, что количество пар (j, k) , для которых j ≤ k, а j и k взаимно просты, равно числу пар (k, j), которые удовлетворяют тем же условиям. Также, если j = k , j = 1 = k .

Таким образом, чтобы подсчитать количество пар простых чисел с координатами от 1 до n , достаточно вычислить количество m пар (j, k), такое что j ≤ k , а затем вычислить 2m - 1 .

Наконец, так как общая функция Эйлера φ (k) дает целые числа между 1 и k , которые взаимно просты с k , мы можем вычислить m как φ (1) +… + φ (n) .

Код

RÆṪSḤ’÷²    Input: n

R           Yield [1, ..., n].
 ÆṪ         Apply Euler's totient function to each k in [1, ..., n].
   S        Compute the sum of all results.
    Ḥ       Multiply the result by 2.
     ’      Subtract 1.
      ÷²    Divide the result by n².

2
О, желе включает в себя функцию totient !? Хорошая идея!
Луис Мендо

2
Обратный отсчет до MATL включает в себя тотальное командование в день Т-1 ...
Quintopia

@quintopia (я, наконец, включил функцию totient) :-D
Луис Мендо

14

Mathematica 43 42 байта

Я нашел точки решетки, видимые из источника , из которого взята картинка ниже, чтобы помочь переосмыслить проблему с помощью следующих вопросов, касающихся данной квадратной области единичной решетки:

  • Какая часть точек единичной решетки имеет взаимно простые координаты?
  • Какую долю единичных решеточных точек можно увидеть из начала координат?

сетка


N@Mean[Mean/@Boole@Array[CoprimeQ,{#,#}]]&

Примеры

Конечные нули опущены.

N@Mean[Mean/@Boole@Array[CoprimeQ,{#,#}]]&/@Range@10

{1, 0,75, 0,777778, 0,6875, 0,76, 0,638889, 0,714286, 0,671875, 0,679012, 0,63}


тайминг

Время в секундах предшествует ответу.

N@Mean[Mean/@Boole@Array[CoprimeQ,{#,#}]]&[1000]// AbsoluteTiming

{0.605571, 0.608383}



6

Mathematica, 42 32 байта

Count[GCD~Array~{#,#},1,2]/#^2.&

Анонимная функция, использует простую грубую силу. Последний случай выполняется на моей машине примерно за .37 секунд. Объяснение:

                               &   A function taking N and returning
Count[               , , ]           the number of
                      1               ones
                                     in the
                        2             second
                                     level of
         ~Array~                      a matrix of
      GCD                              the greatest common denominators of
                {#,#}                 all 2-tuples in [1..N]
                          /         divided by
                           #          N
                            ^2.      squared.

Можете ли вы опубликовать пример прогона и объяснения для тех из нас, у кого нет Mathematica?
Луис Мендо

2
Это объединяет наши представления: Count[Array[GCD,{#, #}],1,2]/#^2.& будь моим гостем.
DavidC

4

Дьялог АПЛ, 15 байт

(+/÷⍴)∘∊1=⍳∘.∨⍳

Довольно просто. Это монадический функциональный поезд. Йота - это числа от 1 до ввода, поэтому мы берем внешнее произведение по gcd, а затем подсчитываем пропорцию единиц.


3

Октава, 49 47 байт

Просто подсчитать gcdвсе пары и посчитать .

@(n)mean(mean(gcd(c=kron(ones(n,1),1:n),c')<2))

Продукт Kronecker потрясающий.


kron! Отличная идея!
Луис Мендо

Сначала я использовал meshgrid, но потом заметил, что могу сделать то же самое с kroninline! (-> анонимная функция)
flawr

2

JavaScript (ES6), 88 байт

n=>eval(`p=0;for(i=n;i;i--)for(j=n;j;j--,p+=a)for(a=1,k=j;k>1;k--)a=i%k||j%k?a:0;p/n/n`)

объяснение

n=>
  eval(`                     // use eval to enable for loop without {} or return
    p=0;                     // p = number of pairs
    for(i=n;i;i--)           // i = 1 to n
      for(j=n;j;j--,p+=a)    // j = i to n, a will equal 1 if i and j are coprime, else 0
        for(a=1,k=j;k>1;k--) // for each number from 0 to j
          a=i%k||j%k?a:0;    // if i%k and j%k are both 0, this pair is not coprime
    p/n/n                    // return result (equivalent to p/(n*n))
  `)

Тест

Требуется некоторое время для больших ( >100) значений n.


2

Серьезно, 15 байтов

,;ª)u1x`▒`MΣτD/

Шестнадцатеричный дамп:

2c3ba62975317860b1604de4e7442f

Попробуйте онлайн

Я не собираюсь объяснять это, поскольку он буквально использует тот же алгоритм, что и решение Денниса Желе (хотя я получил его независимо).


2

J, 19 17 байт

*:%~1-~5+/@p:|@i:

Использование:

   (*:%~1-~5+/@p:|@i:) 4
0.6875

Объяснение:

*:%~1-~5+/@p:|@i:
               i: [-n..n]
             |@   absolute value of each element ([n..1,0,1,..n])
       5+/@p:     sum of the totient function for each element
    1-~           decreased by one, giving the number of co-prime pairs
*:%~              divided by N^2

Решение Денниса дает хорошее объяснение, как мы можем использовать функцию totient.

Попробуйте это онлайн здесь.


2

Mathematica, 35 байт

Реализует алгоритм @ Денниса.

(2`4Plus@@EulerPhi@Range[#]-1)/#^2&

Вычислите сумму коэффициента (фи-функцию Эйлера) в диапазоне от 1 до входного значения. Умножьте на число с плавающей запятой два (с точностью до четырех цифр) и вычтите одно. (Больше точности можно сохранить, используя вместо " 2" и "1`4 ".) Это общее количество пар взаимно простых чисел, поэтому разделите их на квадрат ввода, чтобы получить искомую дробь. Потому что два приблизительное число, так и результат.

Тестирование (с данными о времени в левом столбце, так как по крайней мере один из нас считает это интересным), с функцией, назначенной fтак, чтобы тестовая строка была легче читаемой.

f=(2`4Plus@@EulerPhi@Range[#]-1)/#^2&
RepeatedTiming[f[#]] & /@ {1, 2, 4, 10, 100, 1000}
(* {{5.71*10^-6, 1.000}, 
    {5.98*10^-6, 0.750}, 
    {0.000010  , 0.6875}, 
    {0.0000235 , 0.6300}, 
    {0.00028   , 0.6087}, 
    {0.0033    , 0.6084} }  *)

Редактировать: Показывать экстент диапазона входных данных (меняя точность на единицу вместо двух, потому что в противном случае результаты становятся довольно монотонными) и призывая других делать то же самое ...

f = (2 Plus @@ EulerPhi@Range[#] - 1`4)/#^2 &
{#}~Join~RepeatedTiming[f[#]] & /@ {1, 2, 4, 10, 100, 1000, 10^4, 10^5, 10^6, 10^7}
(*  Results are {input, wall time, output}
    {{       1,  5.3*10^-6, 1.000}, 
     {       2,  6.0*10^-6, 0.7500}, 
     {       4,  0.0000102, 0.68750}, 
     {      10,  0.000023 , 0.63000}, 
     {     100,  0.00028  , 0.6087000}, 
     {    1000,  0.0035   , 0.608383000}, 
     {   10000,  0.040    , 0.60794971000}, 
     {  100000,  0.438    , 0.6079301507000}, 
     { 1000000,  4.811    , 0.607927104783000}, 
     {10000000, 64.0      , 0.60792712854483000}}  *)

RepeatedTiming[]выполняет вычисления несколько раз и занимает среднее время, пытаясь игнорировать холодные кэши и другие эффекты, вызывающие выбросы времени. Асимптотический предел

N[6/Pi^2,30]
(*  0.607927101854026628663276779258  *)

поэтому для аргументов> 10 ^ 4 мы можем просто вернуть «0,6079» и соответствовать указанным требованиям к точности и точности.


2

Юлия, 95 байт

n->(c=combinations([1:n;1:n],2);((L=length)(collect(filter(x->gcd(x...)<2,c)))÷2+1)/L(∪(c)))

Просто прямой подход на данный момент; Я рассмотрю более короткие / более элегантные решения в ближайшее время. Это анонимная функция, которая принимает целое число и возвращает число с плавающей точкой. Чтобы вызвать его, присвойте его переменной.

Ungolfed:

function f(n::Integer)
    # Get all pairs of the integers from 1 to n
    c = combinations([1:n; 1:n], 2)

    # Get the coprime pairs
    p = filter(x -> gcd(x...) == 1, c)

    # Compute the probability
    return (length(collect(p)) ÷ 2 + 1) / length(unique(c))
end

Насколько я могу судить, вам не нужен collectленивый объект, чтобы взять его length.
кот

@cat Вы делаете для некоторых, где lengthне определен метод, как здесь для итератора отфильтрованных комбинаций. Точно так же endofне будет работать, потому что нет метода для этого типа getindex.
Алекс А.


@cat rangeне возвращает объект того же типа, что и combinations. Последний возвращает итератор для комбинаций, который является отдельным типом без определенного lengthметода. Смотрите здесь . (Также :синтаксис предпочтительнее rangeдля построения диапазонов;))
Алекс А.

2

Sage, 55 байтов

lambda a:n((sum(map(euler_phi,range(1,a+1)))*2-1)/a**2)

Благодаря тому, что Sage вычисляет все символически, проблемы с эпсилонами и числами с плавающей запятой не возникают. Компромисс заключается в том, чтобы следовать правилу выходного формата, необходим дополнительный вызов n()(функция десятичной аппроксимации).

Попробуйте онлайн


Очень хорошо! Вы, кажется, используете Sage довольно часто в последнее время :-)
Луис Мендо,

@LuisMendo Sage великолепен и делает все. Это очень хорошо использовать для математических задач, потому что он имеет огромную встроенную библиотеку, такую ​​как Mathematica, но синтаксис лучше (в силу того, что a) не является Mathematica и b) построен на Python).
Mego

2

MATL , 20 17 байт

Это использует текущая версия (5.0.0) языка.

Подход, основанный на ответе @ flawr .

i:tg!X*t!Zd1=Y)Ym

Изменить (28 апреля 2015 г.) : попробуйте онлайн! После того, как этот ответ был опубликован, функцияY) была переименована в X: ; ссылка включает это изменение.

пример

>> matl i:tg!X*t!Zd1=Y)Ym
> 100
0.6087

объяснение

i:         % vector 1, 2, ... up to input number
tg!        % copy, convert into ones, transpose
X*         % Kronecker product. Produces a matrix
t!         % copy, transpose
Zd         % gcd of all pairs
1=         % is it equal to 1?
Y)         % linearize into column array
Ym         % compute mean

Старый ответ: 20 байт

Oi:t"t@Zd1=sb+w]n2^/

объяснение

O             % produce literal 0. Initiallizes count of co-prime pairs.
i             % input number, say N
:             % create vector 1, 2, ... N
t             % duplicate of vector
"             % for loop
    t         % duplicate of vector
    @         % loop variable: each element from vector
    Zd        % gcd of vector and loop variable. Produces a vector
    1=s       % number of "1" in result. Each "1" indicates co-primality
    b+w       % accumulate into count of co-prime pairs
]             % end
n2^/          % divide by N^2

Не могли бы вы быть еще короче с подходом, подобным тому, который я использовал в октаве?
Flawr

Верно! Спасибо! На 3 байта меньше. Вы должны были сделать это самостоятельно в MATL :-)
Луис Мендо

Я бы попробовал, если бы не было времени до сна =)
flawr

1

PARI / GP , 25 байтов

Создание анонимной функции сэкономило бы байт, но тогда мне пришлось бы использовать selfего в целом , чтобы сделать его дороже.

f(n)=n^2-sum(j=2,n,f(n\j))

1

фактор, 120 113 байтов

Я провел урок игры в гольф, и я не могу получить его короче.

Перевод: Юлия .

[ [a,b] dup append 2 <combinations> [ members ] keep [ first2 coprime? ] filter [ length ] bi@ 2 /i 1 + swap /f ]

Пример запускается на первых 5 тестовых примерах (значение 1000 заставляет его заморозить редактор, и я не могу быть обеспокоен компиляцией исполняемого файла прямо сейчас):

! with floating point division
IN: scratchpad auto-use {
      1    
      2    
      4    
      10   
      100  
    }
    [ 
      [1,b] dup append 2 <combinations> [ members ] keep 
      [ first2 coprime? ] filter [ length ] bi@ 2 /i 1 + swap /f 
    ]
    map

--- Data stack:
{ 1.0 0.75 0.6875 0.63 0.6087 }
! with rational division
IN: scratchpad auto-use {
      1    
      2    
      4    
      10   
      100  
    }
    [ 
      [1,b] dup append 2 <combinations> [ members ] keep 
      [ first2 coprime? ] filter [ length ] bi@ 2 /i 1 + swap / 
    ]
    map

--- Data stack:
{ 1.0 0.75 0.6875 0.63 0.6087 }
{ 1 3/4 11/16 63/100 6087/10000 }

Добавить пример запуска может быть?
Луис Мендо

1
@ LuisMendo сделано!
кот

1

Самау , 12 байт

Отказ от ответственности: не участвует, потому что я обновил язык после того, как вопрос был опубликован.

▌;\φΣ2*($2^/

Шестнадцатеричный дамп (Samau использует кодировку CP737):

dd 3b 5c ad 91 32 2a 28 24 32 5e 2f

Используя тот же алгоритм, что и ответ Денниса в Jelly.


0

Python2 / Pypy, 178 байт

xФайл:

N={1:set([1])}
n=0
c=1.0
e=input()
while n<e:
 n+=1
 for d in N[n]:
  m=n+d
  try:N[m].add(d)
  except:N[m]=set([d,m])
 for m in range(1,n):
  if N[m]&N[n]==N[1]:c+=2
print c/n/n

Бег:

$ pypy x <<<1
1.0
$ pypy x <<<10
0.63
$ pypy x <<<100
0.6087
$ pypy x <<<1000
0.608383

Код подсчитывает пары взаимно простых чисел (n,m) for m<nдважды ( c+=2). Это игнорирует, (i,i) for i=1..nчто в порядке, за исключением (1,1), таким образом, исправляется путем инициализации счетчика с 1( 1.0чтобы подготовиться к делению поплавка позже) для компенсации.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.