A tarefa é simplesmente ver quanto mais rápido você pode calcular n, escolha n / 2 (para n mesmo) que a função interna em python. Obviamente, para n grande, esse é um número bastante grande; portanto, em vez de gerar o número inteiro, você deve gerar a soma dos dígitos. Por exemplo, para n = 100000
, a resposta é 135702
. Pois n=1000000
é 1354815
.
Aqui está o código python:
from scipy.misc import comb
def sum_digits(n):
r = 0
while n:
r, n = r + n % 10, n / 10
return r
sum_digits(comb(n,n/2,exact=True))
Sua pontuação é (highest n on your machine using your code)/(highest n on your machine using my code)
. Seu código deve terminar em 60 segundos ou menos.
Seu programa deve fornecer a saída correta para todos os n pares: 2 <= n <= (seu n mais alto)
Você não pode usar nenhum código ou biblioteca interna que calcule coeficientes binomiais ou valores que podem ser rapidamente transformados em coeficientes binomiais.
Você pode usar qualquer idioma de sua escolha.
Resposta principal A resposta principal atual, com um incrível 680,09, é just justhalf.
n
muitos milhões, enquanto eu duvido que a função Python lidaria com algo maior do quen = 1e5
sem engasgar.Respostas:
C ++ (BPF) - (287.000.000 / 422.000) = 680,09
Sem vergonha, combine o Teorema de Kummer por xnor e GMP por qwr.
Ainda nem perto da solução Go, não sei por quê.Edit: Obrigado Keith Randall pelo lembrete de que a multiplicação é mais rápida se o número for semelhante em tamanho. Implementei a multiplicação em vários níveis, semelhante ao conceito de coalescência de memória no gerenciamento de memória. E o resultado é impressionante. O que costumava levar 51s, agora leva apenas 0,5s (ou seja, melhoria de 100 vezes !!)
A corrida por
n=287,000,000
O código. Ajuntar com
-lgmp -lgmpxx -O3
fonte
n
18s calculando o coeficiente binomial central e o restante 37s na conversão do resultado em sequência e somando o dígito.Ir, 33,96 = (16300000/480000)
Funciona contando todos os fatores primos no numerador e denominador e cancelando os fatores correspondentes. Multiplica as sobras para obter o resultado.
Mais de 80% do tempo é gasto na conversão para a base 10. Deve haver uma maneira melhor de fazer isso ...
fonte
Python 3 (8,8 = 2,2 milhões / 0,25 milhão)
Isso é em Python, que não é conhecido por velocidade, então você provavelmente pode fazer melhor portando isso para outro idioma.
Primes gerador retirado deste concurso StackOverflow .
A idéia principal do algoritmo é usar o Teorema de Kummer para obter a fatoração primária do binomial. Para cada primo, aprendemos o poder mais alto dele que divide a resposta e multiplicamos o produto em execução pelo poder do primo. Dessa maneira, precisamos multiplicar apenas uma vez para cada primo na fatoração do primo da resposta.
Saída mostrando a divisão do tempo:
Surpreendentemente, a maior parte do tempo é gasta convertendo o número em uma string para somar seus dígitos. Surpreendentemente, a conversão para uma string foi muito mais rápida do que obter dígitos repetidos
%10
e//10
, mesmo que toda a string deva ser mantida na memória.Gerar os primos leva um tempo insignificante (e, portanto, não me sinto injusto ao copiar o código existente). A soma de dígitos é rápida. A multiplicação real leva um terço do tempo.
Dado que a soma de dígitos parece ser o fator limitante, talvez um algoritmo para multiplicar números na representação decimal economize tempo no total, pressionando a conversão binária / decimal.
fonte
Java (pontuação 22500/365000 = 0,062)
Eu não tenho Python nesta máquina, portanto, se alguém pudesse pontuar isso, ficaria grato. Caso contrário, terá que esperar.
O gargalo é o complemento para calcular a seção relevante do triângulo de Pascal (90% do tempo de execução), portanto, usar um algoritmo de multiplicação melhor não ajudaria.
Observe que o que a pergunta chama
n
é o que eu chamo2n
. O argumento da linha de comando é o que a pergunta chaman
.fonte
javac CodeGolf37270.java
) e executando com Java 1.8 (java CodeGolf37270 n
). Não sei se existem opções de otimização que não conheço. Eu não posso tentar compilar com Java 1.8, porque ele não é instalado com o meu pacote Java ...GMP - 1500000/300000 = 5,0
Embora essa resposta não concorra com peneiras, às vezes o código curto ainda pode obter resultados.
fonte
Java, classe inteira grande personalizada: 32.9 (120000000/365000)
A classe principal é bem direta:
Ele conta com uma grande classe inteira que é otimizada para multiplicação e
toString()
, os quais são gargalos significativos em uma implementação comjava.math.BigInteger
.O grande gargalo é a multiplicação ingênua (60%), seguida pela outra multiplicação (37%) e peneiramento (3%). A
digsum()
ligação é insignificante.Desempenho medido com o OpenJDK 7 (64 bits).
fonte
Python 2 (PyPy), 1.134.000 / 486.000 = 2,32
Resultado: 1.537.506
Curiosidade: o gargalo do seu código está adicionando os dígitos, não computando o coeficiente binomial.
fonte
Java (2.020.000 / 491.000) = 4,11
atualizado, anteriormente 2.24
Java
BigInteger
não é o triturador de números mais rápido, mas é melhor que nada.A fórmula básica para isso parece ser
n! / ((n/2)!^2)
, mas isso parece um monte de multiplicação redundante.Você pode obter uma aceleração significativa eliminando todos os fatores primos encontrados no numerador e no denominador. Para fazer isso, eu primeiro corro uma simples peneira primária. Então, para cada primo, mantenho uma contagem de que poder precisa ser aumentado. Incremente cada vez que vejo um fator no numerador, diminua para o denominador.
Lido com dois separadamente (e primeiro), já que é fácil contá-los / eliminá-los antes de fatorar.
Feito isso, você tem a quantidade mínima de multiplicações necessária, o que é bom porque a multiplicação do BigInt é lenta .
Ah, e a soma da saída para n = 2020000 é
2735298
, para fins de verificação.fonte