Kenapa x**4.0
lebih cepat dari itu x**4
? Saya menggunakan CPython 3.5.2.
$ python -m timeit "for x in range(100):" " x**4.0"
10000 loops, best of 3: 24.2 usec per loop
$ python -m timeit "for x in range(100):" " x**4"
10000 loops, best of 3: 30.6 usec per loop
Saya mencoba mengubah kekuatan yang saya naikkan untuk melihat bagaimana kerjanya, dan misalnya jika saya menaikkan x ke kekuatan 10 atau 16, ia melonjak dari 30 menjadi 35, tetapi jika saya menaikkan sebesar 10,0 sebagai pelampung, itu hanya bergerak sekitar 24.1 ~ 4.
Saya kira itu ada hubungannya dengan konversi float dan kekuatan 2 mungkin, tapi saya tidak benar-benar tahu.
Saya perhatikan bahwa dalam kedua kasus, kekuatan 2 lebih cepat, saya kira karena perhitungan tersebut lebih asli / mudah bagi juru bahasa / komputer. Tapi tetap saja, dengan mengapung itu hampir tidak bergerak. 2.0 => 24.1~4 & 128.0 => 24.1~4
tapi 2 => 29 & 128 => 62
TigerhawkT3 menunjukkan bahwa itu tidak terjadi di luar loop. Saya memeriksa dan situasinya hanya terjadi (dari apa yang saya lihat) ketika pangkalan dinaikkan. Ada ide tentang itu?
python
performance
python-3.x
python-3.5
python-internals
arieljannai
sumber
sumber
x**4.0
dan 3,9 untukx**4
.Jawaban:
int
Objek Python 3 adalah objek penuh yang dirancang untuk mendukung ukuran sewenang-wenang; karena fakta itu, mereka ditangani seperti itu pada level C (lihat bagaimana semua variabel dinyatakan sebagaiPyLongObject *
tipelong_pow
). Ini juga membuat eksponensial mereka jauh lebih rumit dan melelahkan karena Anda perlu bermain-main denganob_digit
array yang digunakannya untuk mewakili nilainya untuk melakukannya. ( Sumber untuk pemberani. - Lihat: Memahami alokasi memori untuk bilangan bulat besar di Python untuk informasi lebih lanjutPyLongObject
.)float
Objek Python , sebaliknya, dapat ditransformasikan kedouble
tipe C (dengan menggunakanPyFloat_AsDouble
) dan operasi dapat dilakukan dengan menggunakan tipe-tipe asli tersebut . Ini bagus karena, setelah memeriksa tepi-kasus yang relevan, memungkinkan Python untuk menggunakan platformpow
( Cpow
, yaitu ) untuk menangani eksponensial yang sebenarnya:di mana
iv
daniw
asliPyFloatObject
s sebagai Cdouble
s.Fakta sebelumnya juga menjelaskan perbedaan antara Python 2 dan 3 jadi, saya pikir saya akan membahas komentar ini juga karena itu menarik.
Di Python 2, Anda menggunakan
int
objek lama yang berbeda dariint
objek di Python 3 (semuaint
objek dalam 3.xPyLongObject
bertipe). Di Python 2, ada perbedaan yang tergantung pada nilai objek (atau, jika Anda menggunakan akhiranL/l
):The
<type 'int'>
Anda lihat di sini melakukan hal yang samafloat
s lakukan , itu akan aman diubah menjadi Clong
ketika eksponensial dilakukan di atasnya (yangint_pow
juga mengisyaratkan compiler untuk menempatkan 'em di register jika dapat melakukannya, sehingga bisa membuat perbedaan) :ini memungkinkan untuk mendapatkan kecepatan yang baik.
Untuk melihat bagaimana lambannya
<type 'long'>
s dibandingkan dengan<type 'int'>
s, jika Anda membungkusx
nama dalamlong
panggilan dengan Python 2 (pada dasarnya memaksanya untuk digunakanlong_pow
seperti pada Python 3), kenaikan kecepatan menghilang:Perhatikan bahwa, meskipun satu cuplikan mengubah
int
kelong
sementara yang lain tidak (seperti yang ditunjukkan oleh @pydsinger), pemeran ini bukanlah kekuatan penyumbang di balik perlambatan. Implementasinyalong_pow
adalah. (Hitung waktu pernyataan hanya denganlong(x)
melihat).Ini adalah pengoptimal lubang intip CPython melipat konstanta untuk Anda. Anda mendapatkan ketepatan waktu yang sama, karena tidak ada perhitungan yang sebenarnya untuk menemukan hasil eksponensial, hanya memuat nilai:
Kode byte identik dihasilkan
'4 ** 4.'
dengan satu-satunya perbedaan adalah bahwaLOAD_CONST
memuat float,256.0
bukan int256
:Jadi waktunya identik.
* Semua hal di atas hanya berlaku untuk CPython, implementasi referensi dari Python. Implementasi lain mungkin berkinerja berbeda.
sumber
range
, karena hanya pengaturan waktu**
operasi itu sendiri tidak menghasilkan perbedaan antara bilangan bulat dan mengapung.4**4
hanya secepat4**4.0
), dan jawaban ini tidak menyentuh itu sama sekali.dis(compile('4 ** 4', '', 'exec'))
) sehingga waktunya harus persis sama.long(x)**2.
masih lebih cepat daripadalong(x)**2
dengan faktor 4-5. (Bukan salah satu dari downvoters)<type 'long'>
jenis Python 3 mungkin dijelaskan oleh upaya yang dilakukan untuk menyederhanakan bahasa. Jika Anda dapat memiliki satu jenis untuk mewakili bilangan bulat, itu lebih mudah dikelola daripada dua (dan khawatir tentang konversi dari satu ke yang lain bila perlu, pengguna menjadi bingung dll). Gain kecepatan adalah sekunder dari itu. Bagian pemikiran PEP 237 juga menawarkan beberapa wawasan lebih banyak.Jika kita melihat bytecode, kita dapat melihat bahwa ekspresi itu murni identik. Satu-satunya perbedaan adalah jenis konstanta yang akan menjadi argumen
BINARY_POWER
. Jadi itu pasti karenaint
sedang dikonversi ke nomor floating point di telepon.Pembaruan: mari kita lihat Objects / abstract.c dalam kode sumber CPython:
PyNumber_Power
panggilanternary_op
, yang terlalu panjang untuk ditempelkan di sini, jadi inilah tautannya .Itu panggilan
nb_power
slotx
, lewaty
sebagai argumen.Akhirnya,
float_pow()
pada baris 686 dari Objects / floatobject.c kita melihat bahwa argumen dikonversikan menjadi Cdouble
tepat sebelum operasi aktual:sumber
float_pow
ketika itu bahkan tidak berjalan untuk kasing lambat?4**4
dan4**4.0
dapatkan lipatan konstan. Itu adalah efek yang sepenuhnya terpisah.Karena yang satu benar, yang lain adalah aproksimasi.
sumber