เพราะเหตุใดจึงx**4.0 ได้เร็วขึ้นกว่าx**4ในหลาม 3 * ?
intวัตถุPython 3 เป็นวัตถุที่เต็มเปี่ยมที่ออกแบบมาเพื่อรองรับขนาดที่กำหนดเอง เนื่องจากความจริงนั้นพวกเขาจะจัดการเช่นนี้ในระดับ C (ดูวิธีการประกาศตัวแปรทั้งหมดเป็นPyLongObject *ประเภทในlong_pow) สิ่งนี้ยังทำให้การยกกำลังของพวกเขายุ่งยากและน่าเบื่อมากขึ้นเนื่องจากคุณต้องเล่นกับob_digitอาเรย์ที่มันใช้เพื่อแทนค่าของมันเพื่อดำเนินการ ( แหล่งที่มาสำหรับผู้กล้า - ดู: ทำความเข้าใจเกี่ยวกับการจัดสรรหน่วยความจำสำหรับจำนวนเต็มขนาดใหญ่ใน Pythonสำหรับข้อมูลเพิ่มเติมเกี่ยวกับPyLongObjects)
งูหลาม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 doubles
สำหรับสิ่งที่มีค่า: 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'>คุณเห็นที่นี่จะเป็นสิ่งเดียวกันfloats ทำมันได้รับการแปลงอย่างปลอดภัยเป็น 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 การใช้งานอื่น ๆ อาจทำงานแตกต่างกัน