Java和Python实现的速度

时间:2014-12-06 13:12:33

标签: java python performance big-o

所以我有一个问题,我已经在python和java中解决了。问题是,对于8000 * 8000个元素的乘法表,找到所有唯一的数字:

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)

爪哇:

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实现的速度?

4 个答案:

答案 0 :(得分: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)

我的电脑需要14秒。 但很明显,python需要更长时间才能解决数学问题,因为Python没有集成的JIT-Compiler。对于计算,有一个名为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.8秒。与C版本相比,只需要0.6秒。

答案 1 :(得分:0)

Python可能会更慢,但请将以下两个片段视为更多pythonic:

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并不是最快的。 python的优点是你可以编写

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

基本上是一个明确解决潜在数学问题的单线程,即定义一个集合并打印其基数。

答案 2 :(得分:0)

问题似乎在于如何在python中创建数组。

请考虑以下事项:

array = []

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

这需要很长时间才能运行(对我来说是14秒),因为我们首先创建一个空数组,然后调整它总共64000001次。您应该创建一个正确大小的数组,而不是这样做,这样只需要一个内存分配:

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

这段代码几乎立即就出现了。

答案 3 :(得分: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语句)。