python数值计算速度_为什么Python在数值计算上这么慢?

考虑下面的代码,它是解决计算几何中“对圆问题”的方法,即找到与最大数量的非相交圆相交的直线。在

这里的主要问题是为什么Python代码比C++代码慢42x。是不是因为Python使用不当?还是因为Python天生就比算术和数学运算的C++慢?有什么办法可以让它更快一点吗?在

首先,Python代码:from __future__ import division

from math import sqrt, atan2, pi

from sys import stdin

__author__ = "Sahand Saba"

EPS = 1e-6

class Point(object):

__slots__ = ['x', 'y']

def __init__(self, xx=0.0, yy=0.0):

self.x = float(xx)

self.y = float(yy)

def angle(self):

"""

Returns the angle the point makes with the x-axis,

counter-clockwise. Result is in the [0, 2*pi) range.

"""

a = atan2(self.y, self.x)

if a < 0:

a = 2 * pi + a

return a

class Circle(object):

__slots__ = ['center', 'radius']

def __init__(self, center, radius):

self.center = center

self.radius = float(radius)

def common_tangents(self, other):

"""

Returns [[p1,p2],[q1,q2]] with p1, p2, q1, q2 all Point objects

representing points on C1 such that the tangent lines to C1 at p1, p2,

q1, q2 are tangent to C2 as well. Further more, p1 and p2 represent

external tangent lines, while q1 and q2 represent internal ones. It is

also guaranteed that p1 and q1 are both on the left-side of the line

connecting C1.center to C2.center, and p2 and q2 are on the right-side

of it.

"""

C1, C2 = self, other

mu = C1.center.x - C2.center.x

eta = C1.center.y - C2.center.y

r1 = C1.radius

r2 = C2.radius

r1r1 = r1 * r1

r1r2 = r1 * r2

delta1 = r1r1 - r1r2

delta2 = r1r1 + r1r2

mumu = mu * mu

etaeta = eta * eta

D = etaeta + mumu

result = [[], []]

if abs(D) < EPS:

return result

if abs(eta) < EPS:

# In this case there is symmetry along the x-axis and we can

# not divide by eta. Use x^2 + y^2 = r^2 to find y.

dmu = -1 if mu < 0 else 1

x = (-delta1 * mu) / D

y = -dmu * sqrt(r1r1 - x * x)

result[0].append(Point(x, y))

result[0].append(Point(x, -y))

x = (-delta2 * mu) / D

y = -dmu * sqrt(r1r1 - x * x)

result[1].append(Point(x, y))

result[1].append(Point(x, -y))

else:

# Here, the symmetry is along the line connecting the two centers.

# Use the equation eta*y + mu *x + r1^2 - r1 * r2 = 0 to derive y

# since we can divide by eta.

dd1 = delta1 * delta1

dd2 = delta2 * delta2

Delta1 = sqrt(dd1 * mumu - D*(dd1 - etaeta * r1r1))

Delta2 = sqrt(dd2 * mumu - D*(dd2 - etaeta * r1r1))

deta = -1 if eta < 0 else 1

x = (-delta1 * mu + deta * Delta1) / D

result[0].append(Point(x, -(mu*x + delta1)/eta))

x = (-delta1 * mu - deta * Delta1) / D

result[0].append(Point(x, -(mu*x + delta1)/eta))

x = (-delta2 * mu + deta * Delta2) / D

result[1].append(Point(x, -(mu*x + delta2)/eta))

x = (-delta2 * mu - deta * Delta2) / D

result[1].append(Point(x, -(mu*x + delta2)/eta))

return result

def add_events(A, p, q):

start = p.angle()

end = q.angle()

A.append((start, 1, p))

A.append((end, -1, q))

return 1 if start > end else 0

def max_intersecting_line(C):

"""

Given a list of circles, returns (m, c, p) where m is the maximal number of

circles in C any line can intersect, and p is a point on a circle c in C

such that the tangent line to c at p intersects m circles in C.

"""

global_max = 1

solution_circle = C[0]

solution_point = Point(C[0].radius, 0.0)

for c1 in C:

local_max = 1

A = []

for c2 in (c for c in C if c is not c1):

Q = c1.common_tangents(c2)

t1 = add_events(A, Q[1][0], Q[0][0])

t2 = add_events(A, Q[0][1], Q[1][1])

local_max += max(t1, t2)

if local_max > global_max:

global_max = local_max

solution_point = Point(c1.radius, 0.0)

solution_circle = c1

A.sort(key=lambda a: a[0])

for a in A:

local_max += a[1]

if local_max > global_max:

global_max = local_max

solution_point = Point(c1.center.x + a[2].x,

c1.center.y + a[2].y)

solution_circle = c1

return global_max, solution_circle, solution_point

if __name__ == '__main__':

T = int(stdin.readline())

for __ in xrange(T):

n = int(stdin.readline())

C = []

for i in xrange(n):

x, y, r = tuple(stdin.readline().split(' '))

C.append(Circle(Point(x, y), r))

print max_intersecting_line(C)[0]

和线等价C++代码的几乎行:

^{pr2}$

以及它们的性能差异:$ time ./janeway < io/Janeway.in > /dev/null

real 0m8.436s

user 0m8.430s

sys 0m0.003s

$ time python janeway.py < io/Janeway.in > /dev/null

real 5m57.899s

user 5m57.217s

sys 0m0.165s

正如你所见,C++代码的速度是42倍。在

(测试输入来自ACM ICPC regional 2013年的问题。参见2013年的http://www.acmicpc-pacnw.org/results.htm问题“Janeway”。)

编辑:下面是Python代码的cProfile输出:799780565 function calls in 507.293 seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)

1 0.000 0.000 0.000 0.000 __future__.py:48()

1 0.000 0.000 0.000 0.000 __future__.py:74(_Feature)

7 0.000 0.000 0.000 0.000 __future__.py:75(__init__)

1 0.047 0.047 507.293 507.293 janeway.py:1()

25 63.703 2.548 507.207 20.288 janeway.py:103(max_intersecting_line)

1 0.000 0.000 0.000 0.000 janeway.py:11(Point)

24250014 5.671 0.000 5.671 0.000 janeway.py:116()

96926032 9.343 0.000 9.343 0.000 janeway.py:127()

96955733 57.902 0.000 57.902 0.000 janeway.py:14(__init__)

96926032 46.840 0.000 63.156 0.000 janeway.py:18(angle)

1 0.000 0.000 0.000 0.000 janeway.py:29(Circle)

18506 0.009 0.000 0.009 0.000 janeway.py:32(__init__)

24231508 167.128 0.000 245.945 0.000 janeway.py:36(common_tangents)

48463016 59.402 0.000 129.139 0.000 janeway.py:95(add_events)

48463016 4.106 0.000 4.106 0.000 {abs}

96926032 16.315 0.000 16.315 0.000 {math.atan2}

48463016 4.908 0.000 4.908 0.000 {math.sqrt}

24231508 9.483 0.000 9.483 0.000 {max}

193870570 18.503 0.000 18.503 0.000 {method 'append' of 'list' objects}

1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}

18532 0.009 0.000 0.009 0.000 {method 'readline' of 'file' objects}

18506 43.918 0.002 53.261 0.003 {method 'sort' of 'list' objects}

18506 0.007 0.000 0.007 0.000 {method 'split' of 'str' objects}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值