Este é um acompanhamento de Quão lento é realmente o Python? (Ou quão rápido é o seu idioma?) .
Aconteceu que foi um pouco fácil obter uma aceleração de x100 para minha última pergunta. Para aqueles que gostaram do desafio, mas querem algo mais difícil, onde realmente podem usar suas habilidades de baixo nível, aqui está a parte II. O desafio é obter uma aceleração de x100 para o seguinte código python, testado no meu computador.
Para tornar mais difícil, estou usando o pypy neste momento. O tempo atual para mim é de 1 minuto e 7 segundos usando o pypy 2.2.1.
Regras
- A primeira pessoa a enviar o código que eu posso executar, está correta e é 100 vezes mais rápida na minha máquina, receberá uma recompensa de 50 pontos.
- Atribuirei a vitória ao código mais rápido depois de uma semana.
import itertools
import operator
import random
n = 8
m = 8
iters = 1000
# creates an array of 0s with length m
# [0, 0, 0, 0, 0, 0, 0, 0]
leadingzerocounts = [0]*m
# itertools.product creates an array of all possible combinations of the
# args passed to it.
#
# Ex:
# itertools.product("ABCD", "xy") --> Ax Ay Bx By Cx Cy Dx Dy
# itertools.product("AB", repeat=5) --> [
# ('A', 'A', 'A', 'A', 'A'),
# ('A', 'A', 'A', 'A', 'B'),
# ('A', 'A', 'A', 'B', 'A'),
# ('A', 'A', 'A', 'B', 'B'),
# etc.
# ]
for S in itertools.product([-1,1], repeat = n+m-1):
for i in xrange(iters):
F = [random.choice([-1,0,0,1]) for j in xrange(n)]
# if the array is made up of only zeros keep recreating it until
# there is at least one nonzero value.
while not any(F):
F = [random.choice([-1,0,0,1]) for j in xrange(n)]
j = 0
while (j < m and sum(map(operator.mul, F, S[j:j+n])) == 0):
leadingzerocounts[j] +=1
j += 1
print leadingzerocounts
A saída deve ser semelhante a
[6335185, 2526840, 1041967, 439735, 193391, 87083, 40635, 19694]
Você deve usar uma semente aleatória no seu código e qualquer gerador de números aleatórios que seja bom o suficiente para fornecer respostas próximas ao acima será aceito.
Minha máquina Os horários serão executados na minha máquina. Esta é uma instalação padrão do ubuntu em um processador AMD FX-8350 de oito núcleos. Isso também significa que eu preciso poder executar seu código.
Explicação do código
Esse código itera sobre todas as matrizes S de comprimento n + m-1 compostas por -1s e 1s. Para cada matriz S, são amostradas 1000 matrizes aleatórias diferentes de zero, F, de comprimento n, compostas de -1,0 ou 1, com probabilidade de 1/4, 1/2 / / 14 de obter cada valor. Ele calcula os produtos internos entre F e cada janela de S de comprimento n até encontrar um produto interno diferente de zero. Ele adiciona 1 a leadingzerocounts
cada posição em que encontrou um produto interno zero.
Status
Perl . 2,7 vezes mais lento por @tobyink. (Comparado com pypy, não cpython.)
J . 39 vezes acelerado por @Eelvex.
- C . 59 vezes mais rápido por @ace.
- Julia . 197 vezes mais rápido, sem incluir o tempo de inicialização por mais um minuto. Acelerar 8,5 vezes, incluindo o tempo de inicialização (neste caso, é mais rápido usar 4 processadores do que 8).
- Fortran . 438 vezes mais rápido por @ semi-extrínseco.
- Rpython . 258 vezes mais rápido por @primo.
- C ++ . 508 vezes mais rápido por @ilmale.
(Parei de cronometrar as novas melhorias porque elas são muito rápidas e o iter era muito pequeno.)
Observou-se que os intervalos abaixo de um segundo não são confiáveis e também alguns idiomas têm um custo inicial. O argumento é que, se você incluir, inclua também o tempo de compilação do C / C ++ etc. Aqui estão os horários para o código mais rápido, com o número de iterações aumentado para 100.000.
- Julia . 42 segundos por mais um minuto.
- C ++ . 14 segundos por @GuySirton.
- Fortran . 14s por @ semi-extrínseco.
- C ++ . 12s por @ilmale.
- Rpython . 18s por @primo.
- C ++ . 5s por @Stefan.
O vencedor é .. Stefan!
Desafio de acompanhamento publicado. Quão alto você pode ir? (Um desafio de codificação + algoritmos) . Este é mais difícil.