x**.5와 math.sqrt(x) 중 어느 쪽이 Python에서 더 빠릅니까?
한동안 궁금했어요.제목에서 알 수 있듯이 실제 기능과 단순히 절반의 출력 중 어느 것이 더 빠릅니까?
갱신하다
이것은 섣부른 최적화의 문제가 아닙니다.이것은 기본적인 코드가 실제로 어떻게 동작하는지에 대한 단순한 질문입니다.Python 코드가 어떻게 동작하는지에 대한 이론은 무엇입니까?
저는 이 방법들의 차이점을 알고 싶어서 Guido van Rossum에게 이메일을 보냈습니다.
내 이메일:
Python의 제곱근에는 math.sqrt, '**' 연산자 및 pow(x,.5)의 3가지 방법이 있습니다.각각의 구현의 차이가 궁금할 뿐입니다.효율에 관한 한 어떤 것이 더 나을까요?
그의 답변:
pow 와 ** 는 동일합니다.math.sqrt 는 복소수에서는 동작하지 않으며 C sqrt() 함수에 링크됩니다.어느 쪽이 빠른지...
math.sqrt(x)
하게 빠르다x**0.5
.
import math
N = 1000000
%%timeit
for i in range(N):
z=i**.5
10루프, 베스트 3: 루프당 156밀리초
%%timeit
for i in range(N):
z=math.sqrt(i)
10개의 루프, 베스트 오브 3: 91.1 ms/루프
Python 3.6.9 (노트북) 사용.
- 최적화 제1규칙: 하지 말 것
- 두 번째 규칙: 아직 하지 마세요.
타이밍은 다음과 같습니다(Python 2.5.2, Windows).
$ python -mtimeit -s"from math import sqrt; x = 123" "x**.5"
1000000 loops, best of 3: 0.445 usec per loop
$ python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
1000000 loops, best of 3: 0.574 usec per loop
$ python -mtimeit -s"import math; x = 123" "math.sqrt(x)"
1000000 loops, best of 3: 0.727 usec per loop
에서는, 「」가x**.5
빠르다sqrt(x)
.
Python 3.0의 경우 결과는 반대입니다.
$ \Python30\python -mtimeit -s"from math import sqrt; x = 123" "x**.5"
1000000 loops, best of 3: 0.803 usec per loop
$ \Python30\python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
1000000 loops, best of 3: 0.695 usec per loop
$ \Python30\python -mtimeit -s"import math; x = 123" "math.sqrt(x)"
1000000 loops, best of 3: 0.761 usec per loop
math.sqrt(x)
x**.5
(Ubuntu, Python 2.6, 3.1):
$ python -mtimeit -s"from math import sqrt; x = 123" "x**.5"
10000000 loops, best of 3: 0.173 usec per loop
$ python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
10000000 loops, best of 3: 0.115 usec per loop
$ python -mtimeit -s"import math; x = 123" "math.sqrt(x)"
10000000 loops, best of 3: 0.158 usec per loop
$ python3.1 -mtimeit -s"from math import sqrt; x = 123" "x**.5"
10000000 loops, best of 3: 0.194 usec per loop
$ python3.1 -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
10000000 loops, best of 3: 0.123 usec per loop
$ python3.1 -mtimeit -s"import math; x = 123" "math.sqrt(x)"
10000000 loops, best of 3: 0.157 usec per loop
벤치마크에서는, 「」가 됩니다.math.sqrt
는, 검색 가 느려집니다.sqrt
를 입력합니다.이 기능을 사용하면
from math import sqrt
에 걸쳐 만, 개, 4, 포(4~5에 대해서 .x**.5
흥미롭게도, 하는 것은
import math
sqrt = math.sqrt
속도가 1% 이내까지 향상되었지만 통계적으로 유의미한 것은 거의 없었습니다.
Kibbee를 반복합니다.그리고 이것은 아마도 너무 이른 최적화라고 말할 것입니다.
실제로 몇 제곱근을 수행하나요?파이썬으로 3D 그래픽 엔진을 쓰려고 하십니까?만약 그렇지 않다면, 왜 읽기 쉬운 코드보다 암호 같은 코드를 선택했을까요?시차는 내가 볼 수 있는 거의 모든 어플리케이션에서 사람들이 알아차릴 수 있는 것보다 적을 것이다.질문을 내리려는 것은 아니지만, 너무 성급하게 최적화하는 것 같습니다.
2.에서는 python 2.6을 합니다.(float).__pow__()
는 C를 합니다.pow()
및 「」의math.sqrt()
는 C를 합니다.sqrt()
★★★★★★ 。
에서는 glibc의 pow(x,y)
매우 복잡하고 다양한 예외적인 경우에 최적화되어 있습니다.를 들어 C를 C를 호출하는 경우pow(x,0.5)
""를 호출합니다.sqrt()
★★★★★★ 。
.**
★★★★★★★★★★★★★★★★★」math.sqrt
는 C 함수 주변에서 사용되는 래퍼에 의해 발생하며 속도는 시스템에서 사용되는 최적화 플래그/C 컴파일러에 따라 크게 달라집니다.
편집:
다음은 클라우디우의 기계 알고리즘 결과입니다.다른 결과를 얻었습니다.
zoltan@host:~$ python2.4 p.py
Took 0.173994 seconds
Took 0.158991 seconds
zoltan@host:~$ python2.5 p.py
Took 0.182321 seconds
Took 0.155394 seconds
zoltan@host:~$ python2.6 p.py
Took 0.166766 seconds
Took 0.097018 seconds
그게 무슨 의미가 있는지는 (짐의 답을 참조)내 머신에서 python 2.5를 실행하고 있는 경우:
PS C:\> python -m timeit -n 100000 10000**.5
100000 loops, best of 3: 0.0543 usec per loop
PS C:\> python -m timeit -n 100000 -s "import math" math.sqrt(10000)
100000 loops, best of 3: 0.162 usec per loop
PS C:\> python -m timeit -n 100000 -s "from math import sqrt" sqrt(10000)
100000 loops, best of 3: 0.0541 usec per loop
Claudiu의 코드를 사용하면 "from math import sqrt" x**.5도 빨라지지만 psyco.full() sqrt(x)를 사용하는 것은 200% 이상 빨라집니다.
Quake 3의 "빠른 뉴턴-라프슨 제곱근"에 대해 어떤 분이 댓글을 달아주셨는데...ctype으로 실장했지만 네이티브 버전에 비해 매우 느립니다.몇 가지 최적화와 대체 구현을 시도해 보겠습니다.
from ctypes import c_float, c_long, byref, POINTER, cast
def sqrt(num):
xhalf = 0.5*num
x = c_float(num)
i = cast(byref(x), POINTER(c_long)).contents.value
i = c_long(0x5f375a86 - (i>>1))
x = cast(byref(i), POINTER(c_float)).contents.value
x = x*(1.5-xhalf*x*x)
x = x*(1.5-xhalf*x*x)
return x * num
여기 구조를 사용하는 또 다른 방법이 있는데, ctypes 버전보다 약 3.6배 빠르지만 속도는 C의 1/10입니다.
from struct import pack, unpack
def sqrt_struct(num):
xhalf = 0.5*num
i = unpack('L', pack('f', 28.0))[0]
i = 0x5f375a86 - (i>>1)
x = unpack('f', pack('L', i))[0]
x = x*(1.5-xhalf*x*x)
x = x*(1.5-xhalf*x*x)
return x * num
math.sqrt(x)는 제곱근에 최적화되어 있기 때문에 가장 가능성이 높습니다.
벤치마크를 통해 원하는 답을 얻을 수 있습니다.
최적화할 수 있는 것은 가독성입니다.이를 위해, 나는 의 명시적인 사용이 생각됩니다.sqrt
기능이 최고입니다.이치노
Claudiu의 Python 3용 코드를 업데이트하고 계산을 최적화할 수 없도록 했습니다(향후 Python 컴파일러가 할 수 있는 일).
from sys import version
from time import time
from math import sqrt, pi, e
print(version)
N = 1_000_000
def timeit1():
z = N * e
s = time()
for n in range(N):
z += (n * pi) ** .5 - z ** .5
print (f"Took {(time() - s):.4f} seconds to calculate {z}")
def timeit2():
z = N * e
s = time()
for n in range(N):
z += sqrt(n * pi) - sqrt(z)
print (f"Took {(time() - s):.4f} seconds to calculate {z}")
def timeit3(arg=sqrt):
z = N * e
s = time()
for n in range(N):
z += arg(n * pi) - arg(z)
print (f"Took {(time() - s):.4f} seconds to calculate {z}")
timeit1()
timeit2()
timeit3()
결과는 다양하지만 출력 예는 다음과 같습니다.
3.6.6 (default, Jul 19 2018, 14:25:17)
[GCC 8.1.1 20180712 (Red Hat 8.1.1-5)]
Took 0.3747 seconds to calculate 3130485.5713865166
Took 0.2899 seconds to calculate 3130485.5713865166
Took 0.2635 seconds to calculate 3130485.5713865166
그리고 최근 출력은 다음과 같습니다.
3.7.4 (default, Jul 9 2019, 16:48:28)
[GCC 8.3.1 20190223 (Red Hat 8.3.1-2)]
Took 0.2583 seconds to calculate 3130485.5713865166
Took 0.1612 seconds to calculate 3130485.5713865166
Took 0.1563 seconds to calculate 3130485.5713865166
Claudiu의 결과는 나와 다르다.오래된 P4 2.4Ghz 기계에서 Ubuntu에서 Python 2.6을 사용하고 있습니다.결과는 다음과 같습니다.
>>> timeit1()
Took 0.564911 seconds
>>> timeit2()
Took 0.403087 seconds
>>> timeit1()
Took 0.604713 seconds
>>> timeit2()
Took 0.387749 seconds
>>> timeit1()
Took 0.587829 seconds
>>> timeit2()
Took 0.379381 seconds
sqrt가 일관되게 더 빠릅니다.심지어 Codepad.org NOW도 로컬 컨텍스트에서 sqrt가 더 빠르다는 것에 동의하는 것 같습니다(http://codepad.org/6trzcM3j)).코드패드는 현재 Python 2.5를 실행하고 있는 것 같습니다.Claudiu가 처음 대답했을 때 그들은 2.4 또는 그 이상을 사용하고 있었을까요?
실제로 arg(i) 대신 math.sqrt(i)를 사용해도 sqrt에 대한 시간이 더 좋습니다.이 경우 timeit2()는 머신에서 0.53~0.55초 소요되며, 이는 timeit1의 0.56~0.60 수치보다 더 좋습니다.
현대의 Python에서는 math.sqrt를 사용하여 somevar=math.sqrt 또는 math import sqrt에서 로컬 컨텍스트로 가져옵니다.
물론 리터럴을 다루고 있고 일정한 값이 필요한 경우 연산자를 사용하여 작성된 경우 Python 런타임은 컴파일 시 값을 미리 계산할 수 있습니다. 이 경우 각 버전을 프로파일링할 필요가 없습니다.
In [77]: dis.dis(a)
2 0 LOAD_CONST 1 (1.4142135623730951)
2 RETURN_VALUE
In [78]: def a():
...: return 2 ** 0.5
...:
In [79]: import dis
In [80]: dis.dis(a)
2 0 LOAD_CONST 1 (1.4142135623730951)
2 RETURN_VALUE
안녕하세요! 이 대화에 참여하기 위해 스택 익스체인지 프로필을 만들었습니다!내가 하고 있는 일이 사소한 것처럼 보일 수도 있지만, 판단하기 전에 내 말을 한 번 들어 봐.
실험 조건:
- 오프라인(인터넷 컴파일러 문제 없음)
- 시스템 상태를 가능한 한 안정적으로 유지
- 한 번에 3가지 기능을 모두 테스트합니다.
원래 질문에서 설명한 각 기능에 대해 각각 5회씩 3루프를 실행했습니다.그리고 각 루프의 정수 제곱근을 0에서 10^8까지 계산했습니다.
결과는 다음과 같습니다.소요 시간:sqrt(x)
< >x**0.5
< >pow(x, 0.5)
주의: 두 자리 수 초 차이로 10^8이 넘는 음이 아닌 정수.
출력 스크린샷:출력
결론:
저는 Guido의 이메일이 이러한 타이밍을 정당화한다고 생각합니다.다음 문장을 고려해 주십시오.
math.sqrt()
C에 링크하여 복잡한 번호는 사용하지 않습니다.**
★★★★★★★★★★★★★★★★★」pow()
가 됩니다.
는 '이렇게 하다'라는 것을 할 수 .**
★★★★★★★★★★★★★★★★★」pow()
둘 다 전달된 입력이 복소수인지 확인해야 하기 때문에 정수를 전달하더라도 어느 정도의 오버헤드 비용이 발생합니다.게다가 복합번호는 Python에 내장되어 있으며, Python 코드를 쓰기 위해 Python을 사용하는 것은 컴퓨터에서 작업하는 것입니다.
그리고 특히,math.sqrt()
이는 Complex Number 인수를 확인하는 번거로움을 겪지 않아도 되며 일반적인 Python보다 약간 빠른 것으로 증명된 C 언어 함수와 직접 연결되기 때문입니다.
이 결론에서 당신의 의견이 제 의견과 다를 경우 알려주시기 바랍니다!
코드:
import time
import math
print("x**0.5 : ")
for _ in range(5):
start = time.time()
for i in range(int(1e8)):
i**0.5
end = time.time()
print(end-start)
print("math.sqrt(x) : ")
for _ in range(5):
start = time.time()
for i in range(int(1e8)):
math.sqrt(i)
end = time.time()
print(end-start)
print("pow(x,0.5) : ")
for _ in range(5):
start = time.time()
for i in range(int(1e8)):
pow(i,0.5)
end = time.time()
print(end-start)
최근에 해결한 SQRMINSUM 문제는 대규모 데이터 집합에서 제곱근을 반복적으로 계산해야 합니다.다른 최적화를 실시하기 전에 가장 오래된2개의 제출은 **0.5를 sqrt()로 대체하여 실행시간을 3.74초에서 PyPy로 0.51초로 줄였습니다.이는 Claudiu가 측정한 400%의 대폭적인 개선률의 거의 두 배에 달하는 수치입니다.
더 빠른 것은 math.py에 접속하여 "http" 함수를 프로그램에 복사하는 것입니다.프로그램이 math.py을 검색하여 열고 원하는 기능을 찾은 후 프로그램으로 되돌리려면 시간이 걸립니다."lookup" 단계에서도 그 기능이 더 빠르면 기능 자체가 매우 빨라야 합니다.아마 시간을 절반으로 줄일 수 있을 거야요약:
- math.py 에 접속합니다.
- 함수 "sqrt"를 찾습니다.
- 카피
- 함수를 sqrt finder로 프로그램에 붙여넣습니다.
- 시간을 재다.
언급URL : https://stackoverflow.com/questions/327002/which-is-faster-in-python-x-5-or-math-sqrtx
'programing' 카테고리의 다른 글
mysql의 max(길이(필드)) (0) | 2022.11.08 |
---|---|
Java에서의 합성 클래스 (0) | 2022.11.08 |
리액트 후크 useState()와 오브젝트 (0) | 2022.11.07 |
mariadb 이미지에 대해 루트 사용자가 아닌 도커 컨테이너를 실행할 수 없습니다. (0) | 2022.11.07 |
Chrome에서 탭이 비활성 상태일 때 setInterval도 작동하도록 하려면 어떻게 해야 합니까? (0) | 2022.11.07 |