เพราะเหตุใดจึงx**4.0
ได้เร็วขึ้นกว่าx**4
ในหลาม 3 * ?
int
วัตถุPython 3 เป็นวัตถุที่เต็มเปี่ยมที่ออกแบบมาเพื่อรองรับขนาดที่กำหนดเอง เนื่องจากความจริงนั้นพวกเขาจะจัดการเช่นนี้ในระดับ C (ดูวิธีการประกาศตัวแปรทั้งหมดเป็นPyLongObject *
ประเภทในlong_pow
) สิ่งนี้ยังทำให้การยกกำลังของพวกเขายุ่งยากและน่าเบื่อมากขึ้นเนื่องจากคุณต้องเล่นกับob_digit
อาเรย์ที่มันใช้เพื่อแทนค่าของมันเพื่อดำเนินการ ( แหล่งที่มาสำหรับผู้กล้า - ดู: ทำความเข้าใจเกี่ยวกับการจัดสรรหน่วยความจำสำหรับจำนวนเต็มขนาดใหญ่ใน Pythonสำหรับข้อมูลเพิ่มเติมเกี่ยวกับPyLongObject
s)
งูหลามfloat
วัตถุในทางที่สามารถเปลี่ยนไปยัง C double
ประเภท (โดยการใช้PyFloat_AsDouble
) และการดำเนินงานสามารถดำเนินการได้โดยใช้ประเภทพื้นเมืองเหล่านั้น นี่เป็นสิ่งที่ยอดเยี่ยมเพราะหลังจากตรวจสอบกรณีขอบที่เกี่ยวข้องจะช่วยให้ Python ใช้แพลตฟอร์ม 'pow
( ของ C pow
นั่นคือ ) เพื่อจัดการการยกกำลังจริง:
/* Now iv and iw are finite, iw is nonzero, and iv is
* positive and not equal to 1.0. We finally allow
* the platform pow to step in and do the rest.
*/
errno = 0;
PyFPE_START_PROTECT("pow", return NULL)
ix = pow(iv, iw);
ที่ไหนiv
และiw
เป็นต้นฉบับของเราPyFloatObject
เป็น C double
s
สำหรับสิ่งที่มีค่า: Python 2.7.13
สำหรับฉันเป็นปัจจัยที่2~3
เร็วกว่าและแสดงพฤติกรรมผกผัน
ความจริงก่อนหน้านี้ยังอธิบายถึงความแตกต่างระหว่าง Python 2 และ 3 ดังนั้นฉันคิดว่าฉันจะพูดถึงความคิดเห็นนี้เพราะมันน่าสนใจ
ใน Python 2 คุณกำลังใช้int
วัตถุเก่าที่แตกต่างจากint
วัตถุใน Python 3 ( int
วัตถุทั้งหมดใน 3.x เป็นPyLongObject
ประเภท) ใน Python 2 มีความแตกต่างที่ขึ้นอยู่กับมูลค่าของวัตถุ (หรือถ้าคุณใช้คำต่อท้ายL/l
):
# Python 2
type(30) # <type 'int'>
type(30L) # <type 'long'>
<type 'int'>
คุณเห็นที่นี่จะเป็นสิ่งเดียวกันfloat
s ทำมันได้รับการแปลงอย่างปลอดภัยเป็น C long
เมื่อยกกำลังจะดำเนินการกับมัน (คนint_pow
นอกจากนี้ยังมีคำแนะนำคอมไพเลอร์ที่จะนำ 'em ในการลงทะเบียนถ้ามันสามารถทำได้เพื่อให้สามารถสร้างความแตกต่าง) :
static PyObject *
int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z)
{
register long iv, iw, iz=0, ix, temp, prev;
/* Snipped for brevity */
สิ่งนี้จะช่วยให้ได้รับความเร็วที่ดี
หากต้องการดูว่าการทำงานของคนเกียจคร้าน<type 'long'>
เปรียบเทียบกับ<type 'int'>
s อย่างไรหากคุณใส่x
ชื่อไว้ในการlong
โทรใน Python 2 (บังคับให้ใช้long_pow
ใน Python 3 เป็นหลัก) ความเร็วจะหายไป:
# <type 'int'>
(python2) ➜ python -m timeit "for x in range(1000):" " x**2"
10000 loops, best of 3: 116 usec per loop
# <type 'long'>
(python2) ➜ python -m timeit "for x in range(1000):" " long(x)**2"
100 loops, best of 3: 2.12 msec per loop
โปรดทราบว่าแม้ว่าข้อมูลโค้ดหนึ่งจะแปลงint
ไปเป็นlong
ในขณะที่อีกตัวอย่างหนึ่งไม่ได้ (ตามที่ระบุโดย @ pydsinger) นักแสดงนี้ไม่ได้เป็นกำลังที่สนับสนุนเบื้องหลังการชะลอตัว การดำเนินการของlong_pow
คือ (เวลางบเพียงlong(x)
เพื่อดู)
[... ] มันไม่ได้เกิดขึ้นนอกวง [... ] มีความคิดเกี่ยวกับเรื่องนี้ไหม?
นี่คือเครื่องมือเพิ่มประสิทธิภาพช่องมองของ CPython พับค่าคงที่สำหรับคุณ คุณจะได้รับการกำหนดเวลาที่แน่นอนเหมือนกันทั้งสองกรณีเนื่องจากไม่มีการคำนวณจริงเพื่อค้นหาผลลัพธ์ของการยกกำลังเพียงแค่โหลดค่า:
dis.dis(compile('4 ** 4', '', 'exec'))
1 0 LOAD_CONST 2 (256)
3 POP_TOP
4 LOAD_CONST 1 (None)
7 RETURN_VALUE
รหัสไบต์ที่เหมือนกันถูกสร้างขึ้น'4 ** 4.'
โดยมีความแตกต่างเพียงอย่างเดียวที่LOAD_CONST
โหลดลอย256.0
แทน int 256
:
dis.dis(compile('4 ** 4.', '', 'exec'))
1 0 LOAD_CONST 3 (256.0)
2 POP_TOP
4 LOAD_CONST 2 (None)
6 RETURN_VALUE
ดังนั้นเวลาจึงเท่ากัน
* ทั้งหมดข้างต้นมีผลบังคับใช้สำหรับ CPython เท่านั้นการใช้งานอ้างอิงของ Python การใช้งานอื่น ๆ อาจทำงานแตกต่างกัน