Co-primalidade e o número pi


23

Introdução

A teoria dos números está cheia de maravilhas, na forma de conexões inesperadas. Aqui está um deles.

Dois inteiros são co-prime se eles não têm fatores em comum que não seja 1. Dado um número N , considere todos os inteiros de 1 a N . Desenhe dois números inteiros aleatoriamente (todos os números inteiros têm a mesma probabilidade de serem selecionados a cada sorteio; os sorteios são independentes e com substituição). Vamos p denotar a probabilidade de que os dois números inteiros selecionados sejam co-primos. Então p tende a 6 / π 2 ≈ 0,6079 ... como N tende ao infinito.

O desafio

O objectivo deste desafio é calcular p como uma função de N .

Como exemplo, considere N = 4. Existem 16 pares possíveis obtidos dos números inteiros 1,2,3,4. 11 desses pares são co-primos, a saber (1,1), (1,2), (1,3), (1,4), (2,1), (3,1), (4,1 ), (2,3), (3,2), (3,4), (4,3). Assim, p é 11/16 = 0,6875 para N = 4.

O valor exato de p precisa ser calculado com pelo menos quatro casas decimais. Isso implica que o cálculo deve ser determinístico (em oposição a Monte Carlo). Mas não precisa ser uma enumeração direta de todos os pares como acima; qualquer método pode ser usado.

Argumentos de função ou stdin / stdout podem ser usados. Se exibir a saída, zeros à direita podem ser omitidos. Por exemplo, 0.6300pode ser exibido como 0.63. Ele deve ser exibido como um número decimal, não como uma fração (exibir a sequência 63/100não é permitido).

O critério de vitória é o menor número de bytes. Não há restrições no uso de funções internas.

Casos de teste

Entrada / saída (apenas quatro casas decimais são obrigatórias, como indicado acima):

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

Existem limites no intervalo de entradas?
Eric Towers

@EricTowers O programa deve funcionar para qualquer tamanho razoável, até as limitações de memória e tipo de dados. Pelo menos 1000
Luis Mendo

Os números racionais são permitidos como valores de retorno (não cadeias)? Minha linguagem tem um tipo racional nativo, no qual 63/100é um literal válido, utilizável em computação. (Langs que estou falando: Fator , Racket )
gato

@cat Claro, vá em frente! Leve em conta a precisão necessária, embora
Luis Mendo

Respostas:


14

Gelatina , 12 8 bytes

RÆṪSḤ’÷²

Experimente online!

O código binário a seguir funciona com esta versão do interpretador Jelly .

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

Idéia

Claramente, o número de pares (j, k), de tal modo que j ≤ k e j e k são co-primo é igual ao número de pares (k, j) que satisfazem as mesmas condições. Além disso, se j = k , j = 1 = k .

Assim, para contar o número de pares co-primos com coordenadas entre 1 e n , basta calcular a quantidade m de pares (j, k) de modo que j ≤ k , depois computar 2m - 1 .

Finalmente, como a função totiente de Euler φ (k) produz o número inteiro entre 1 e k que são co-primos para k , podemos calcular m como φ (1) +… + φ (n) .

Código

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
Oh, Jelly inclui a função totiente !? Boa ideia!
Luis Mendo

2
A contagem regressiva até o MATL inclui um comando totiente no dia T-1 ...
quintopia

@quintopia (eu finalmente incluiu a função totient) :-D
Luis Mendo

14

Mathematica 43 42 bytes

Eu achei os pontos de rede visíveis desde a origem , a partir dos quais a foto abaixo foi tirada, para ajudar a reformular o problema através das seguintes perguntas sobre uma determinada região quadrada da rede de unidades:

  • Que fração dos pontos de unidade-treliça tem coordenadas co-primas?
  • Que fração de pontos de rede unitária pode ser vista a partir da origem?

grade


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

Exemplos

Zeros à direita são omitidos.

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}


Cronometragem

O tempo, em segundos, precede a resposta.

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

{0,605571, 0,608383}



6

Mathematica, 42 32 bytes

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

Função anônima, usa força bruta simples. O último caso ocorre em cerca de 0,37 segundos na minha máquina. Explicação:

                               &   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.

Você pode postar um exemplo de execução e explicação para aqueles que não possuem o Mathematica?
Luis Mendo

2
Isso une nossas submissões: Count[Array[GCD,{#, #}],1,2]/#^2.& Seja meu convidado.
DavidC

4

Dyalog APL, 15 bytes

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

Bem direto. É um trem monádico. Iota são os números de 1 a entrada, por isso pegamos o produto externo por mcd e depois contamos a proporção de um.


3

Oitava, 49 47 bytes

Apenas calculando o gcdde todos os pares e contando.

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

O produto kronecker é incrível.


kron! Boa ideia!
Luis Mendo

Eu usei pela primeira vez meshgrid, mas depois notei que podia fazer o mesmo com o kroninline! (-> função anônima)
flawr

2

JavaScript (ES6), 88 bytes

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`)

Explicação

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))
  `)

Teste

Demora um pouco para >100valores grandes ( ) de n.


2

Sério, 15 bytes

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

Hex Dump:

2c3ba62975317860b1604de4e7442f

Experimente Online

Não vou me incomodar em explicá-lo, pois ele literalmente usa exatamente o mesmo algoritmo da solução Jelly de Dennis (embora eu o tenha derivado de forma independente).


2

J, 19 17 bytes

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

Uso:

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

Explicação:

*:%~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

A solução de Dennis fornece uma boa explicação de como podemos usar a função totiente.

Experimente online aqui.


2

Mathematica, 35 bytes

Implementa o algoritmo de @ Dennis.

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

Calcule a soma do totiente (função phi de Euler) no intervalo de 1 ao valor de entrada. Multiplique pelo ponto flutuante dois (com quatro dígitos de precisão) e subtraia um. (É possível reter mais precisão usando " 2" e " 1`4".) Este é o número total de pares de coprimes, portanto divida pelo quadrado da entrada para obter a fração desejada. Como os dois são um número aproximado, o mesmo ocorre com o resultado.

Teste (com dados de temporização na coluna da esquerda, pois pelo menos um de nós acha isso interessante), com a função atribuída para fque a linha de teste seja mais facilmente lida .:

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} }  *)

Edit: Mostrando a extensão do intervalo de entradas (trocando a precisão por uma em vez das duas porque, caso contrário, os resultados ficam bastante monótonos) e desafiando outras pessoas a fazer o mesmo ...

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[]realiza o cálculo várias vezes e leva uma média dos tempos, tentando ignorar caches frios e outros efeitos, causando discrepâncias de tempo. O limite assintótico é

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

portanto, para argumentos> 10 ^ 4, podemos retornar "0,6079" e atender aos requisitos de precisão e exatidão especificados.


2

Julia, 95 bytes

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

Apenas a abordagem direta por enquanto; Analisarei soluções mais curtas / elegantes em breve. Esta é uma função anônima que aceita um número inteiro e retorna um número flutuante. Para chamá-lo, atribua-o a uma variável.

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

Até onde eu sei, você não precisa de collectum objeto preguiçoso para pegá-lo length.
gato

@cat Você faz em alguns lugares onde lengthnão há um método definido, como é o caso aqui para o iterador de combinações filtradas. Da mesma forma endof, não funcionaria porque não há método para esse tipo getindex.
Alex A.


O @cat rangenão retorna o mesmo tipo de objeto que combinations. O último retorna um iterador sobre combinações, que é um tipo separado, sem lengthmétodo definido . Veja aqui . (Também a :sintaxe é preferido em relação rangepara a construção de intervalos;))
Alex A.

2

Sábio, 55 bytes

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

Graças à Sage computando tudo simbolicamente, os problemas de epsilon e ponto flutuante da máquina não surgem. A compensação é que, para seguir a regra do formato de saída, n()é necessária uma chamada adicional para (a função de aproximação decimal).

Experimente online


Muito agradável! Você parece estar usando Sábio bastante frequência ultimamente :-)
Luis Mendo

@LuisMendo Sage é ótimo e faz todas as coisas. É muito bom usá-lo em desafios baseados em matemática porque possui uma enorme biblioteca interna como o Mathematica, mas a sintaxe é melhor (em virtude de a) não ser o Mathematica eb) ser construída no Python).
Mego

2

MATL , 20 17 bytes

Isso usa a versão atual (5.0.0) do idioma.

Abordagem baseada na resposta de @ flawr .

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

Editar (28 de abril de 2015) : Experimente online! Depois que essa resposta foi postada, a função Y)foi renomeada para X:; o link inclui essa alteração.

Exemplo

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

Explicação

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

Resposta antiga: 20 bytes

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

Explicação

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

Você não poderia ser ainda mais baixo com uma abordagem como a que usei na oitava?
flawr

De fato! Obrigado! 3 bytes a menos. Você deveria ter feito isso sozinho em MATL :-)
Luis Mendo

Eu teria tentado se não fosse muito além da minha hora de dormir =)
flawr

1

PARI / GP , 25 bytes

Tornar a função anônima salvaria um byte, mas então eu teria que usá- selfla, tornando-a mais cara em geral.

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

1

Fator, 120 113 bytes

Passei aulas jogando golfe e não posso ficar mais curto.

Tradução de: Julia .

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

O exemplo é executado nos 5 primeiros casos de teste (um valor de 1000 faz com que congele o editor, e não posso me incomodar em compilar um executável agora):

! 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 }

Adicione um exemplo de execução, talvez?
Luis Mendo

1
@LuisMendo done!
gato

1

Samau , 12 bytes

Isenção de responsabilidade: não competindo porque atualizei o idioma após a publicação da pergunta.

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

Dump hexadecimal (a Samau usa a codificação CP737):

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

Usando o mesmo algoritmo da resposta de Dennis no Jelly.


0

Python2 / Pypy, 178 bytes

O xarquivo:

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

Corrida:

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

O código conta os pares co-prime duas (n,m) for m<nvezes ( c+=2). Isso ignora o (i,i) for i=1..nque está ok, exceto (1,1), sendo assim corrigido inicializando o contador com 1( 1.0para preparar a divisão de flutuação posteriormente) para compensar.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.