Saya tidak mengerti mengapa Python tidak memiliki sign
fungsi. Itu memilikiabs
builtin (yang saya anggap sign
saudara perempuan), tetapi tidaksign
.
Dalam python 2.6 bahkan ada copysign
fungsi (dalam matematika ), tetapi tidak ada tanda. Mengapa repot - repot menulis copysign(x,y)
ketika Anda hanya bisa menulis sign
dan kemudian mendapatkancopysign
langsung dariabs(x) * sign(y)
? Yang terakhir akan jauh lebih jelas: x dengan tanda y, sedangkan dengan copysign Anda harus ingat apakah x dengan tanda y atau y dengan tanda x!
Jelas sekali sign(x)
tidak memberikan apa pun selaincmp(x,0)
, tetapi akan jauh lebih mudah dibaca bahwa ini juga (dan untuk bahasa yang sangat mudah dibaca seperti python, ini akan menjadi nilai tambah yang besar).
Jika saya seorang desainer python, saya akan menjadi sebaliknya: tidak ada cmp
builtin, tapi a sign
. Ketika Anda membutuhkan cmp(x,y)
, Anda bisa melakukan sign(x-y)
(atau, bahkan lebih baik untuk hal-hal non-numerik, hanya x> y - tentu saja ini seharusnya mengharuskan sorted
menerima boolean daripada pembanding integer). Ini juga akan lebih jelas: positif ketika x>y
(sedangkan dengan cmp
Anda harus ingat konvensi positif ketika pertama adalah lebih besar , tapi bisa jalan di sekitar lainnya). Tentu sajacmp
masuk akal sendiri karena alasan lain (misalnya ketika mengurutkan hal-hal non-numerik, atau jika Anda ingin jenis menjadi stabil, yang tidak mungkin digunakan hanya dengan boolean)
Jadi, pertanyaannya adalah: mengapa perancang Python memutuskan untuk meninggalkan sign
fungsi ini dari bahasa? Kenapa sih repot-repot dengan copysign
dan bukan induknya sign
?
Apakah saya melewatkan sesuatu?
EDIT - setelah Peter Hansen berkomentar. Cukup adil sehingga Anda tidak menggunakannya, tetapi Anda tidak mengatakan untuk apa Anda menggunakan python. Dalam 7 tahun saya menggunakan python, saya membutuhkannya berkali-kali, dan yang terakhir adalah sedotan yang mematahkan punggung unta!
Ya, Anda dapat melewati cmp sekitar, tetapi 90% dari waktu yang saya butuhkan untuk lulus itu dalam ungkapan seperti
lambda x,y: cmp(score(x),score(y))
itu akan bekerja dengan tanda baik-baik saja.
Akhirnya, saya harap Anda setuju bahwa sign
akan lebih bermanfaat daripada copysign
, jadi bahkan jika saya membeli pandangan Anda, mengapa repot-repot mendefinisikannya dalam matematika, alih-alih tanda? Bagaimana copysign lebih berguna daripada tanda?
sumber
Jawaban:
EDIT:
Memang ada tambalan yang termasuk
sign()
dalam matematika , tetapi itu tidak diterima, karena mereka tidak setuju tentang apa yang harus dikembalikan dalam semua kasus tepi (+/- 0, +/- nan, dll)Jadi mereka memutuskan untuk mengimplementasikan hanya copysign, yang (walaupun lebih banyak verbose) dapat digunakan untuk mendelegasikan kepada pengguna akhir perilaku yang diinginkan untuk kasus tepi - yang kadang-kadang mungkin memerlukan panggilan untuk
cmp(x,0)
.Saya tidak tahu mengapa itu bukan bawaan, tapi saya punya beberapa pemikiran.
Yang paling penting,
copysign
adalah supersetsign
! Memanggilcopysign
dengan x = 1 sama dengansign
fungsi. Jadi Anda bisa menggunakancopysign
dan melupakannya .Jika Anda bosan melewati dua argumen penuh, Anda bisa menerapkan
sign
cara ini, dan itu masih akan kompatibel dengan hal-hal IEEE yang disebutkan oleh orang lain:Kedua, biasanya ketika Anda menginginkan tanda sesuatu, Anda akhirnya mengalikannya dengan nilai lain. Dan tentu saja itu pada dasarnya apa
copysign
terjadi.Jadi, alih-alih:
Anda bisa melakukannya:
Dan ya, saya terkejut Anda telah menggunakan Python selama 7 tahun dan berpikir
cmp
bisa dengan mudah dihapus dan digantisign
! Pernahkah Anda menerapkan kelas dengan__cmp__
metode? Pernahkah Anda meneleponcmp
dan menetapkan fungsi pembanding khusus?Singkatnya, saya mendapati diri saya menginginkan
sign
fungsi juga, tetapicopysign
dengan argumen pertama menjadi 1 akan berfungsi dengan baik. Saya tidak setuju itusign
akan lebih berguna daripadacopysign
, karena saya telah menunjukkan bahwa itu hanya sebagian dari fungsi yang sama.sumber
[int(copysign(1, zero)) for zero in (0, 0.0, -0.0)]
memberi[1, 1, -1]
. Itu seharusnya[0, 0, 0]
sesuai dengan en.wikipedia.org/wiki/Sign_functioncopysign(a,b)
mengembalikan a dengan tanda b - b adalah input yang bervariasi, a adalah nilai untuk dinormalisasi dengan tanda b. Dalam hal ini, komentator menggambarkan bahwa copysign (1, x) sebagai pengganti tanda (x) gagal, karena mengembalikan 1 untuk x = 0, sedangkan tanda (0) akan dievaluasi menjadi 0.cmp()
akan memberikan hasil yang diinginkan, mungkin untuk hampir setiap kasus siapa pun akan peduli:[cmp(zero, 0) for zero in (0, 0.0, -0.0, -4, 5)]
==>[0, 0, 0, -1, 1]
.s = sign(a) b = b * s
tidak setara denganb = copysign(b, a)
! Tidak mempertimbangkan tanda b. Misalnya jikaa=b=-1
kode pertama akan mengembalikan 1 sedangkan yang kedua mengembalikan -1"copysign" didefinisikan oleh IEEE 754, dan bagian dari spesifikasi C99. Itu sebabnya itu di Python. Fungsi tidak dapat diimplementasikan secara penuh oleh abs (x) * tanda (y) karena bagaimana itu seharusnya menangani nilai-nilai NaN.
Itu membuat copysign () fungsi yang lebih berguna daripada tanda ().
Mengenai alasan spesifik mengapa IEEE's signbit (x) tidak tersedia dalam standar Python, saya tidak tahu. Saya bisa membuat asumsi, tapi itu hanya menebak.
Modul matematika itu sendiri menggunakan copysign (1, x) sebagai cara untuk memeriksa apakah x negatif atau non-negatif. Untuk sebagian besar kasus, berurusan dengan fungsi matematika yang tampaknya lebih berguna daripada memiliki tanda (x) yang mengembalikan 1, 0, atau -1 karena ada satu kasus yang kurang untuk dipertimbangkan. Misalnya, berikut ini dari modul matematika Python:
Di sana Anda dapat dengan jelas melihat bahwa copysign () adalah fungsi yang lebih efektif daripada fungsi tiga-tanda ().
Kau menulis:
Itu berarti Anda tidak tahu bahwa cmp () digunakan untuk hal-hal selain angka. cmp ("Ini", "Itu") tidak dapat diimplementasikan dengan fungsi tanda ().
Edit untuk menyusun jawaban tambahan saya di tempat lain :
Anda mendasarkan pembenaran Anda pada seberapa abs () dan tanda () sering terlihat bersama. Karena pustaka standar C tidak mengandung fungsi 'tanda (x)' dalam bentuk apa pun, saya tidak tahu bagaimana Anda membenarkan pandangan Anda. Ada abs (int) dan fabs (double) dan fabsf (float) dan fabsl (panjang) tetapi tidak menyebutkan tanda. Ada "copysign ()" dan "signbit ()" tetapi itu hanya berlaku untuk nomor IEEE 754.
Dengan bilangan kompleks, tanda apa yang akan (-3 + 4j) kembalikan dalam Python, apakah harus diimplementasikan? abs (-3 + 4j) mengembalikan 5.0. Itu adalah contoh yang jelas tentang bagaimana abs () dapat digunakan di tempat-tempat di mana tanda () tidak masuk akal.
Misalkan tanda (x) ditambahkan ke Python, sebagai pelengkap untuk abs (x). Jika 'x' adalah turunan dari kelas yang ditentukan pengguna yang mengimplementasikan metode __ab __ (self) maka abs (x) akan memanggil x .__ abs __ (). Agar dapat bekerja dengan benar, untuk menangani abs (x) dengan cara yang sama maka Python harus mendapatkan slot tanda (x).
Ini berlebihan untuk fungsi yang relatif tidak dibutuhkan. Selain itu, mengapa tanda (x) ada dan tidak negatif (x) dan tidak positif (x) tidak ada? Cuplikan saya dari implementasi modul matematika Python menunjukkan bagaimana copybit (x, y) dapat digunakan untuk mengimplementasikan nonnegative (), yang tidak dapat dilakukan oleh tanda sederhana (x).
Python seharusnya mendukung memiliki dukungan yang lebih baik untuk fungsi matematika IEEE 754 / C99. Itu akan menambahkan fungsi signbit (x), yang akan melakukan apa yang Anda inginkan dalam kasus floats. Ini tidak akan berfungsi untuk bilangan bulat atau bilangan kompleks, apalagi string, dan tidak akan memiliki nama yang Anda cari.
Anda bertanya "mengapa", dan jawabannya adalah "tanda (x) tidak berguna." Anda menyatakan bahwa itu berguna. Namun komentar Anda menunjukkan bahwa Anda tidak cukup tahu untuk dapat membuat pernyataan itu, yang berarti Anda harus menunjukkan bukti yang meyakinkan tentang kebutuhannya. Mengatakan bahwa NumPy mengimplementasikannya tidak cukup meyakinkan. Anda perlu menunjukkan kasus bagaimana kode yang ada akan ditingkatkan dengan fungsi tanda.
Dan itu di luar lingkup StackOverflow. Bawa saja ke salah satu daftar Python.
sumber
cmp()
atausign()
:-)Satu liner lain untuk tanda ()
Jika Anda ingin mengembalikan 0 untuk x = 0:
sumber
cmp(x, 0)
setara dengansign
, danlambda x: cmp(x, 0)
lebih mudah dibaca daripada apa yang Anda sarankan.-1 if x < 0 else 1
?sign = lambda x: -1 if x < 0 else 1
adalah 15% lebih cepat . Sama dengansign = lambda x: x and (-1 if x < 0 else 1)
.Karena
cmp
telah dihapus , Anda bisa mendapatkan fungsionalitas yang sama dengannyaIni bekerja untuk
float
,int
dan bahkanFraction
. Dalam kasusfloat
, perhatikansign(float("nan"))
adalah nol.Python tidak mengharuskan perbandingan mengembalikan boolean, dan karenanya memaksa perbandingan ke bool () melindungi terhadap penerapan yang diijinkan, tetapi tidak umum:
sumber
Hanya jawaban yang benar yang sesuai dengan definisi Wikipedia
The definisi di Wikipedia berbunyi:
Karenanya,
Yang untuk semua maksud dan tujuan dapat disederhanakan untuk:
Definisi fungsi ini mengeksekusi cepat dan menghasilkan hasil yang benar dijamin untuk 0, 0,0, -0,0, -4 dan 5 (lihat komentar untuk jawaban yang salah lainnya).
Perhatikan bahwa nol (0) tidak positif atau negatif .
sumber
numpy memiliki fungsi tanda, dan memberi Anda bonus fungsi lainnya. Begitu:
Berhati-hatilah karena hasilnya numpy.float64:
Untuk hal-hal seperti json, ini penting, karena json tidak tahu cara membuat serial jenis numpy.float64. Dalam hal ini, Anda dapat melakukan:
untuk mendapatkan pelampung reguler.
sumber
Coba jalankan ini, di mana x adalah angka apa pun
Paksaan ke bool () menangani kemungkinan bahwa operator pembanding tidak mengembalikan boolean.
sumber
Ya
sign()
fungsi yang benar harus setidaknya dalam modul matematika - seperti yang ada di numpy. Karena kita sering membutuhkannya untuk kode berorientasi matematika.Tetapi
math.copysign()
juga bermanfaat secara mandiri.cmp()
danobj.__cmp__()
... secara umum memiliki kepentingan tinggi secara mandiri. Bukan hanya untuk kode yang berorientasi matematika. Pertimbangkan membandingkan / menyortir tupel, objek tanggal, ...Argumen dev di http://bugs.python.org/issue1640 tentang penghilangan
math.sign()
ganjil, karena:-NaN
sign(nan) == nan
tanpa khawatir (sepertiexp(nan)
)sign(-0.0) == sign(0.0) == 0
tanpa khawatirsign(-inf) == -1
tanpa khawatir- Seperti di numpy
sumber
Dalam Python 2,
cmp()
mengembalikan bilangan bulat: tidak ada persyaratan bahwa hasilnya adalah -1, 0, atau 1, jadisign(x)
tidak sama dengancmp(x,0)
.Dalam Python 3,
cmp()
telah dihapus demi perbandingan kaya. Sebabcmp()
, Python 3 menyarankan ini :yang bagus untuk cmp (), tetapi sekali lagi tidak dapat digunakan untuk tanda () karena operator pembanding tidak perlu mengembalikan boolean .
Untuk menghadapi kemungkinan ini, hasil perbandingan harus dipaksa untuk boolean:
Ini berfungsi untuk apa pun
type
yang benar-benar dipesan (termasuk nilai-nilai khusus sukaNaN
atau tak terbatas).sumber
Anda tidak memerlukannya, Anda cukup menggunakan:
sumber
x / abs(x)
dibutuhkan sedikit lebih lama dari sekadar rantaiif/else
untuk memeriksa sisi 0 variabel mana yang aktif, atau dalam hal ini menggunakan slimy-belum-memuaskanreturn (x > 0) - (x < 0)
untuk mengurangibool
nilai dan mengembalikanint
True
danFalse
sebagai1
dan0
, Anda benar-benar dapat melakukan hal ini dan mendapatkan baik1
,0
atau-1
.def sign(x): return (x > 0) - (x < 0)
tidak akan mengembalikanbool
, itu akan mengembalikanint
- jika Anda lulus0
Anda akan0
kembaliHanya saja tidak.
Cara terbaik untuk memperbaikinya adalah:
sumber
Alasan "tanda" tidak disertakan adalah bahwa jika kami menyertakan setiap satu-liner yang berguna dalam daftar fungsi bawaan, Python tidak akan mudah dan praktis untuk digunakan. Jika Anda sering menggunakan fungsi ini maka mengapa Anda tidak memfaktorkannya sendiri? Ini tidak seperti itu sulit atau bahkan membosankan untuk melakukannya.
sumber
abs()
ditinggalkan juga.sign()
danabs()
sering digunakan bersama,sign()
adalah yang paling berguna dari keduanya (IMO), dan tidak ada yang terlalu sulit atau membosankan untuk diimplementasikan (meskipun rentan kesalahan, lihat bagaimana jawaban ini salah: stackoverflow.com/questions/1986152/… )sign()
itu sendiri jarang berguna. Yang paling sering Anda lakukan adalah mengambil jalur kode yang berbeda berdasarkan apakah suatu variabel positif atau negatif, dan dalam hal itu lebih mudah dibaca untuk menulis kondisi secara eksplisit.