2014-12-06 2 views
0

У меня есть проблема, которую я уже решил как в python, так и в java. Проблема заключается в том, для таблицы умножения 8000 * 8000 элементов, найти все уникальные номера:Скорость реализации Java и Python

Python:

table = 8000 
unique_prods = [] 
start = 1 

for i in range(table*table + 1): 
    unique_prods.append(0) 

for x in range(1, table + 1): 
    for y in range(start, table + 1): 
     # print '{:4}'.format(x * y), 
     if not unique_prods[x * y] == x * y: 
      unique_prods[x * y] = x * y 
    start += 1 
    # print 

# print unique_prods 
print len(unique_prods) 

Java:

public class Test { 
    public static void main(String[] args) { 
     int table = 8000; 
     int [] myArray = new int[table*table + 1]; 
     int count = 1; 

     for (int i = 0; i < table*table + 1; i++) { 
      myArray[i] = 0; 
     } 

     for (int x = 1; x < table + 1; x++) { 
      for (int y = count; y < table + 1; y++) { 
       if (! (myArray[x * y] == x * y)) { 
        myArray[x * y] = x * y; 
       } 
      } 
      count += 1; 
//   System.out.println(count); 
     } 

     count = 0; 
     for (int i = 0; i < table*table + 1; i++) { 
      if(myArray[i] != 0) { 
       count += 1; 
      } 
     } 

     System.out.println(count); 
    } 
} 

Я нашел, что это удивительно, что реализация Java занял второе место, и версия Python заняла минуту. Есть ли способ повысить производительность python, чтобы он стал ближе к скорости реализации Java?

+0

О, я видел теперь, что Python выплюнул неправильный ответ, но это можно легко устранить, итерации по списку. Извини за это. –

+1

Почему вы проверяете, не соответствует ли 'myArray [x * y]' 'x * y' перед установкой его равным' x * y'? Если он уже равен, то установка его равным самому себе не изменяет его значение. Если он уже не равен, он будет установлен в 'x * y'. 'If' является излишним. – curiousinternals

+1

'for i in range (table * table + 1): unique_prods.append (0)' следует заменить на 'unique_prods = [0] * (table * table + 1)', что в 15 раз быстрее на моей машине. – PeterE

ответ

2

Ваш код Python не является оптимальным, вы бы не решить проблему так же, как и в Java:

table = 8000 
unique_prods = set() 

for x in range(1, table + 1): 
    for y in range(x, table + 1): 
     unique_prods.add(x * y) 
print len(unique_prods) 

принимает 14s на моем компьютере. Но ясно, что python занимает больше времени для математических задач, потому что у Python нет встроенного JIT-компилятора. Для расчетов, есть пакет под названием NumPy, что ускоряет вещи значительно:

import numpy 
x = numpy.arange(1,8001) 
unique_prods = numpy.zeros(8000*8000+1,dtype='b') 
for k in x: 
    unique_prods[k*x[k-1:]]=1 
print unique_prods.sum() 

и вы получите свой результат в 0.8s. В отличие от версии C, для которой требуется всего 0,6 с.

+0

Очевидно, что Java-версия также должна использовать установленный подход. Так что это не имеет смысла. Либо сравните две оптимальные реализации, либо две неоптимальные. Утверждение, что Python отличается в этом отношении от Java, неверно. – BartoszKP

+0

На моем компьютере подход набора в python проще, но значительно медленнее, чем использование таблицы таблицы таблиц длины. –

+0

Это действительно быстро. Не могли бы вы объяснить, что вы делаете. Я не могу понять строку unique_prods [k * x [k-1:]] = 1 –

0

Python может быть медленнее, но рассмотреть следующие два фрагмента, как все больше вещий:

import time 
starttime = time.time() 
table = 8000 
unique_prods = [0] * (table*table + 1) 
for x in range(1, table+1): 
    for y in range(1, table+1): 
     unique_prods[x*y] = 1 

elapsed = time.time() - starttime 
print((elapsed, sum(unique_prods))) 

и самый простой, но не обязательно быстро:

starttime = time.time() 
table = 8000 
unique = set(x*y for x in range(1, table+1) for y in range(1,table+1)) 
elapsed = time.time() - starttime 
print((elapsed, len(unique))) 

Python не предназначен, чтобы быть быстрый. Преимущество питона является то, что вы можете написать

unique = set(x*y for x in range(1, table+1) for y in range(1,table+1)) 
print(len(unique)) 

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

+0

Используйте 'timeit' более надежное сравнение реализаций. – BartoszKP

+0

И как с другим ответом: нет смысла изменять базовый алгоритм только в одной реализации при сравнении с другим. – BartoszKP

+0

@BartoszKP: Я сравнивал ни с чем, просто показываю некоторые варианты. –

0

Проблема заключается в том, как вы создаете свой массив в python.

Рассмотрим следующий пример:

array = [] 

for i in range(8000*8000 + 1): 
    array.append(0) 

Это заняло много времени, чтобы запустить (14s для меня), потому что мы сначала создать пустой массив, а затем изменить его в общей сложности 64000001 раз. Вместо того, чтобы делать это, вы должны создать массив нужного размера так, что требуется только один выделения памяти:

array = [0] * (8000*8000 + 1) // Creates an array filled with zeros of size (8000*8000 + 1) 

Этот код побежал почти мгновенно для меня.

+0

Вы пытались сравнить всю программу с этим исправлением? – BartoszKP

+0

@BartoszKP Я только что сделал, и это показало, что мой первый тест дал дико неточный результат. Я не уверен, почему в первый раз потребовалось минута вместо 14 секунд (материал работает в фоновом режиме?), Но я предполагаю, что это учит меня повторять тесты. Вернуться к чертежной доске ... – curiousinternals

+0

Для этой цели у Python есть модуль 'timeit'. – BartoszKP

0

Как заметили другие, способ, которым вы расширяете список, - это одно из преимуществ вашей реализации Java в этом алгоритме.Это простое решение проблемы:

unique_prods = [0] * (table*table + 1) 

дает следующие результаты вашего алгоритма (с реализацией в противном случае точно так же из вас уже отвечал):

python -m timeit -n 10 -r 1 "import test" "test.testWithFix()" 
64000001 
64000001 
64000001 
64000001 
64000001 
64000001 
64000001 
64000001 
64000001 
64000001 
10 loops, best of 1: 31.6 sec per loop 

python -m timeit -n 10 -r 1 "import test" "test.testWithoutFix()" 
64000001 
64000001 
64000001 
64000001 
64000001 
64000001 
64000001 
64000001 
64000001 
64000001 
10 loops, best of 1: 62.9 sec per loop 

Кроме того, как ваши реализации (вы должны использовать набор) и иметь другие незначительные неточности (например, избыточное заявление if, упомянутое в комментариях).

Смежные вопросы