Tại sao x**4.0 nhanh hơn x**4trong Python 3 * ?
Các intđối tượng Python 3 là một đối tượng chính thức được thiết kế để hỗ trợ kích thước tùy ý; do thực tế đó, chúng được xử lý như vậy ở cấp độ C (xem cách tất cả các biến được khai báo là PyLongObject *kiểu trong long_pow). Điều này cũng làm cho phép lũy thừa của chúng trở nên phức tạp và tẻ nhạt hơn rất nhiều vì bạn cần phải chơi xung quanh với ob_digitmảng mà nó sử dụng để biểu thị giá trị của nó để thực hiện nó. ( Nguồn cho người dũng cảm. - Xem: Tìm hiểu phân bổ bộ nhớ cho số nguyên lớn trong Python để biết thêm về PyLongObjects.)
floatNgược lại, các đối tượng Python có thể được chuyển đổi thành doubleloại C (bằng cách sử dụng PyFloat_AsDouble) và các hoạt động có thể được thực hiện bằng các loại gốc đó . Này là rất tốt bởi vì, sau khi kiểm tra cho cạnh các trường hợp có liên quan, nó cho phép Python để sử dụng các nền tảngpow ( C pow, có nghĩa là ) để xử lý các lũy thừa thực tế:
/* 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);
ở đâu ivvà iwlà bản gốc của chúng tôi PyFloatObjectlà C doubles.
Đối với những gì nó có giá trị: Python 2.7.13đối với tôi là một yếu tố 2~3nhanh hơn và cho thấy hành vi nghịch đảo.
Thực tế trước đây cũng giải thích sự khác biệt giữa Python 2 và 3 vì vậy, tôi nghĩ tôi cũng sẽ giải quyết nhận xét này vì nó rất thú vị.
Trong Python 2, bạn đang sử dụng intđối tượng cũ khác với intđối tượng trong Python 3 (tất cả intcác đối tượng trong 3.x là PyLongObjectloại). Trong Python 2, có một sự phân biệt phụ thuộc vào giá trị của đối tượng (hoặc, nếu bạn sử dụng hậu tố L/l):
# Python 2
type(30) # <type 'int'>
type(30L) # <type 'long'>
Các <type 'int'>bạn thấy ở đây làm điều tương tự floats làm , nó được một cách an toàn chuyển đổi thành một C long khi lũy thừa được thực hiện trên nó (The int_powcũng gợi ý trình biên dịch để đưa 'em trong một thanh ghi nếu nó có thể làm như vậy, để có thể tạo sự khác biệt) :
static PyObject *
int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z)
{
register long iv, iw, iz=0, ix, temp, prev;
/* Snipped for brevity */
điều này cho phép đạt được tốc độ tốt.
Để xem mức độ chậm chạp <type 'long'>so với <type 'int'>s, nếu bạn gói xtên trong một longcuộc gọi trong Python 2 (về cơ bản buộc nó phải sử dụng long_pownhư trong Python 3), tốc độ tăng sẽ biến mất:
# <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
Xin lưu ý rằng, mặc dù một đoạn biến đổi intthành longtrong khi đoạn kia không (như được chỉ ra bởi @pydsinger), dàn diễn viên này không phải là lực lượng đóng góp đằng sau sự chậm lại. Việc thực hiện long_powlà. (Thời gian báo cáo chỉ long(x)để xem).
[...] Nó không xảy ra bên ngoài vòng lặp. [...] Có ý kiến gì về điều đó không?
Đây là trình tối ưu hóa lổ nhìn trộm của CPython gấp các hằng số cho bạn. Bạn cũng có được thời gian chính xác như nhau vì không có tính toán thực tế để tìm kết quả của lũy thừa, chỉ tải các giá trị:
dis.dis(compile('4 ** 4', '', 'exec'))
1 0 LOAD_CONST 2 (256)
3 POP_TOP
4 LOAD_CONST 1 (None)
7 RETURN_VALUE
Mã byte giống hệt nhau được tạo ra '4 ** 4.'với sự khác biệt duy nhất là LOAD_CONSTtải float 256.0thay vì 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
Vì vậy, thời gian là giống hệt nhau.
* Tất cả những điều trên chỉ áp dụng cho CPython, triển khai tham chiếu của Python. Các triển khai khác có thể thực hiện khác nhau.