>>> (float('inf')+0j)*1
(inf+nanj)
Mengapa? Ini menyebabkan bug buruk dalam kode saya.
Mengapa bukan 1
identitas multiplikatif, memberi(inf + 0j)
?
>>> (float('inf')+0j)*1
(inf+nanj)
Mengapa? Ini menyebabkan bug buruk dalam kode saya.
Mengapa bukan 1
identitas multiplikatif, memberi(inf + 0j)
?
Jawaban:
Pertama, 1
diubah menjadi bilangan kompleks 1 + 0j
, yang kemudian mengarah ke inf * 0
perkalian, menghasilkan a nan
.
(inf + 0j) * 1
(inf + 0j) * (1 + 0j)
inf * 1 + inf * 0j + 0j * 1 + 0j * 0j
# ^ this is where it comes from
inf + nan j + 0j - 0
inf + nan j
1
dilemparkan 1 + 0j
.
array([inf+0j])*1
evaluasi juga ke array([inf+nanj])
. Dengan asumsi bahwa perkalian sebenarnya terjadi di suatu tempat dalam kode C / C ++, apakah ini berarti bahwa mereka menulis kode kustom untuk meniru perilaku CPython, daripada menggunakan _Complex atau std :: complex?
numpy
memiliki satu kelas pusat ufunc
yang darinya hampir setiap operator dan fungsi berasal. ufunc
menangani penyiaran mengelola langkah semua admin rumit yang membuat bekerja dengan array begitu nyaman. Lebih tepatnya pembagian kerja antara operator tertentu dan mesin umum adalah bahwa operator tertentu menerapkan serangkaian "loop terdalam" untuk setiap kombinasi jenis elemen masukan dan keluaran yang ingin ditangani. Mesin umum menangani setiap loop luar dan memilih loop paling dalam yang paling cocok ...
types
atribut untuk np.multiply
hasil ini. ['??->?', 'bb->b', 'BB->B', 'hh->h', 'HH->H', 'ii->i', 'II->I', 'll->l', 'LL->L', 'qq->q', 'QQ->Q', 'ee->e', 'ff->f', 'dd->d', 'gg->g', 'FF->F', 'DD->D', 'GG->G', 'mq->m', 'qm->m', 'md->m', 'dm->m', 'OO->O']
Kita dapat melihat bahwa hampir tidak ada tipe campuran, khususnya, tidak ada yang menggabungkan float "efdg"
dengan kompleks "FDG"
.
Secara mekanis, jawaban yang diterima, tentu saja, benar, tetapi saya berpendapat bahwa jawaban yang lebih dalam dapat diberikan.
Pertama, akan berguna untuk memperjelas pertanyaan seperti yang dilakukan @PeterCordes dalam komentar: "Apakah ada identitas perkalian untuk bilangan kompleks yang berfungsi pada inf + 0j?"atau dengan kata lain adalah apa yang OP melihat kelemahan dalam implementasi komputer perkalian kompleks atau adakah sesuatu yang secara konseptual tidak sehatinf+0j
Dengan menggunakan koordinat kutub kita dapat melihat perkalian kompleks sebagai penskalaan dan rotasi. Memutar "lengan" tak terhingga bahkan sebesar 0 derajat seperti dalam kasus mengalikan dengan satu, kita tidak dapat mengharapkan untuk menempatkan ujungnya dengan presisi terbatas. Jadi memang, ada sesuatu yang secara fundamental tidak benarinf+0j
, yaitu bahwa begitu kita berada pada ketakterhinggaan offset yang terbatas menjadi tidak berarti.
Latar belakang: "Hal besar" yang melingkupi pertanyaan ini adalah masalah perluasan sistem bilangan (pikirkan bilangan real atau bilangan kompleks). Salah satu alasan seseorang mungkin ingin melakukan itu adalah menambahkan beberapa konsep tak terhingga, atau untuk "memadatkan" jika seseorang kebetulan adalah seorang ahli matematika. Ada alasan lain juga ( https://en.wikipedia.org/wiki/Galois_theory , https://en.wikipedia.org/wiki/Non-standard_analysis ), tetapi kami tidak tertarik dengan tersebut di sini.
Hal yang rumit tentang ekstensi seperti itu, tentu saja, kita ingin angka-angka baru ini sesuai dengan aritmatika yang ada. Cara termudah adalah menambahkan satu elemen pada tak terhingga ( https://en.wikipedia.org/wiki/Alexandroff_extension ) dan membuatnya sama dengan apa pun kecuali nol dibagi nol. Ini berfungsi untuk real ( https://en.wikipedia.org/wiki/Projectively_extended_real_line ) dan bilangan kompleks ( https://en.wikipedia.org/wiki/Riemann_sphere ).
Sementara pemadatan satu titik sederhana dan secara matematis terdengar, ekstensi "lebih kaya" yang terdiri dari beberapa infinties telah dicari. Standar IEEE 754 untuk bilangan floating point nyata memiliki + inf dan -inf ( https://en.wikipedia.org/wiki/Extended_real_number_line ). Tampak alami dan lugas tetapi sudah memaksa kita untuk melewati rintangan dan menciptakan hal-hal seperti-0
https://en.wikipedia.org/wiki/Signed_zero
Bagaimana dengan ekstensi lebih dari satu inf dari bidang kompleks?
Di komputer, bilangan kompleks biasanya diimplementasikan dengan menempelkan dua real fp bersama-sama, satu untuk real dan satu untuk bagian imajiner. Itu baik-baik saja selama semuanya terbatas. Namun, segera, karena ketidakterbatasan dianggap hal-hal menjadi rumit.
Bidang kompleks memiliki simetri rotasi alami, yang terikat baik dengan aritmatika kompleks karena mengalikan seluruh bidang dengan e ^ phij sama dengan rotasi phi radian di sekitarnya 0
.
Sekarang, untuk menjaga agar tetap sederhana, fp kompleks cukup menggunakan ekstensi (+/- inf, nan dll.) Dari implementasi bilangan real yang mendasarinya. Pilihan ini mungkin tampak begitu alami bahkan tidak dianggap sebagai pilihan, tapi mari kita lihat lebih dekat apa yang tersirat. Visualisasi sederhana dari perluasan bidang kompleks ini terlihat seperti (I = tak hingga, f = hingga, 0 = 0)
I IIIIIIIII I
I fffffffff I
I fffffffff I
I fffffffff I
I fffffffff I
I ffff0ffff I
I fffffffff I
I fffffffff I
I fffffffff I
I fffffffff I
I IIIIIIIII I
Tetapi karena bidang kompleks yang sebenarnya adalah bidang yang menghormati perkalian kompleks, proyeksi yang lebih informatif akan menjadi
III
I I
fffff
fffffff
fffffffff
I fffffffff I
I ffff0ffff I
I fffffffff I
fffffffff
fffffff
fffff
I I
III
Dalam proyeksi ini kita melihat "distribusi tidak merata" dari ketidakterbatasan yang tidak hanya jelek tetapi juga akar masalah dari jenis yang diderita OP: Kebanyakan ketidakterbatasan (yang berbentuk (+/- inf, finite) dan (finite, + / -inf) disatukan di empat arah utama semua arah lainnya diwakili oleh hanya empat infinities (+/- inf, + -inf). Seharusnya tidak mengherankan bahwa memperluas perkalian kompleks ke geometri ini adalah mimpi buruk .
Lampiran G dari spesifikasi C99 mencoba yang terbaik untuk membuatnya berfungsi, termasuk membengkokkan aturan tentang bagaimana inf
dan nan
berinteraksi (pada dasarnya inf
mengalahkan nan
). Masalah OP dikesampingkan dengan tidak mempromosikan real dan tipe imajiner murni yang diusulkan ke kompleks, tetapi memiliki perilaku 1 yang nyata berbeda dari kompleks 1 tidak menurut saya sebagai solusi. Singkatnya, Lampiran G berhenti menjelaskan secara lengkap apa produk dari dua tak terbatas seharusnya.
Sangat menggoda untuk mencoba dan memperbaiki masalah ini dengan memilih geometri tak terbatas yang lebih baik. Dalam analogi garis real yang diperpanjang kita bisa menambahkan satu tak terhingga untuk setiap arah. Konstruksi ini mirip dengan bidang proyektif tetapi tidak saling bertemu berlawanan arah. Ketidakterbatasan akan direpresentasikan dalam koordinat kutub inf xe ^ {2 omega pi i}, mendefinisikan produk akan menjadi mudah. Secara khusus, masalah OP akan diselesaikan secara alami.
Tapi disinilah kabar baik berakhir. Di satu sisi, kita dapat dilemparkan kembali ke titik awal dengan --- bukan tidak masuk akal --- mengharuskan infinitas gaya baru kita mendukung fungsi yang mengekstrak bagian nyata atau imajinernya. Penambahan adalah masalah lain; menambahkan dua ketidakterbatasan nonantipodal kita harus mengatur sudut ke tidak terdefinisi yaitu nan
(orang dapat berargumen bahwa sudut harus terletak di antara dua sudut masukan tetapi tidak ada cara sederhana untuk menyatakan bahwa "nan-ness parsial")
Mengingat semua ini mungkin pemadatan satu titik yang baik adalah hal yang paling aman untuk dilakukan. Mungkin penulis Lampiran G merasakan hal yang sama ketika mengamanatkan fungsi cproj
yang menggabungkan semua infinitas menjadi satu.
Berikut adalah pertanyaan terkait yang dijawab oleh orang-orang yang lebih kompeten pada materi pelajaran daripada saya.
nan != nan
. Saya mengerti bahwa jawaban ini setengah bercanda, tetapi saya gagal untuk melihat mengapa itu harus membantu OP dalam cara penulisannya.
==
(dan karena mereka menerima jawaban lain), tampaknya itu hanya masalah bagaimana OP mengungkapkan judulnya. Saya mengubah judul untuk memperbaiki ketidakkonsistenan itu. (Sengaja membatalkan paruh pertama jawaban ini karena saya setuju dengan @cmaster: bukan itu yang ditanyakan oleh pertanyaan ini).
Ini adalah detail implementasi tentang bagaimana perkalian kompleks diimplementasikan di CPython. Tidak seperti bahasa lain (misalnya C atau C ++), CPython mengambil pendekatan yang agak sederhana:
Py_complex
_Py_c_prod(Py_complex a, Py_complex b)
{
Py_complex r;
r.real = a.real*b.real - a.imag*b.imag;
r.imag = a.real*b.imag + a.imag*b.real;
return r;
}
Satu kasus bermasalah dengan kode di atas adalah:
(0.0+1.0*j)*(inf+inf*j) = (0.0*inf-1*inf)+(0.0*inf+1.0*inf)j
= nan + nan*j
Namun, seseorang ingin mendapatkan -inf + inf*j
hasilnya.
Dalam hal ini bahasa lain tidak jauh di depan: perkalian bilangan kompleks untuk waktu yang lama bukan bagian dari standar C, termasuk hanya dalam C99 sebagai lampiran G, yang menjelaskan bagaimana perkalian kompleks harus dilakukan - dan itu tidak sesederhana seperti rumus sekolah di atas! Standar C ++ tidak menentukan bagaimana perkalian kompleks harus bekerja, sehingga sebagian besar implementasi compiler kembali ke implementasi C, yang mungkin sesuai dengan C99 (gcc, clang) atau tidak (MSVC).
Untuk contoh "bermasalah" di atas, implementasi yang sesuai dengan C99 (yang lebih rumit daripada rumus sekolah) akan memberikan ( lihat langsung ) hasil yang diharapkan:
(0.0+1.0*j)*(inf+inf*j) = -inf + inf*j
Bahkan dengan standar C99, hasil yang tidak ambigu tidak ditentukan untuk semua input dan mungkin berbeda bahkan untuk versi yang kompatibel dengan C99.
Efek samping lain dari float
tidak dipromosikan complex
di C99 adalah bahwa mengalikan inf+0.0j
dengan 1.0
atau 1.0+0.0j
dapat menghasilkan hasil yang berbeda (lihat di sini langsung):
(inf+0.0j)*1.0 = inf+0.0j
(inf+0.0j)*(1.0+0.0j) = inf-nanj
, bagian imajiner menjadi -nan
dan bukan nan
(seperti untuk CPython) tidak berperan di sini, karena semua nan tenang adalah setara (lihat ini ), bahkan beberapa di antaranya memiliki set tanda-bit (dan dengan demikian dicetak sebagai "-", lihat ini ) dan beberapa tidak.Yang setidaknya kontra-intuitif.
Kuncinya adalah: tidak ada yang sederhana tentang perkalian (atau pembagian) bilangan kompleks yang "sederhana" dan ketika beralih antar bahasa atau bahkan penyusun, seseorang harus mempersiapkan diri untuk bug / perbedaan halus.
printf
dan serupa bekerja dengan ganda: mereka melihat tanda-bit untuk memutuskan apakah "-" harus dicetak atau tidak (tidak peduli apakah itu nan atau tidak). Jadi Anda benar, tidak ada perbedaan yang berarti antara "nan" dan "-nan", segera perbaiki bagian jawaban ini.
Definisi lucu dari Python. Jika kita memecahkan ini dengan pena dan kertas saya akan mengatakan bahwa hasil yang diharapkan akan expected: (inf + 0j)
seperti yang Anda menunjukkan karena kita tahu bahwa kita maksud norma 1
sehingga(float('inf')+0j)*1 =should= ('inf'+0j)
:
Tapi bukan itu masalahnya seperti yang Anda lihat ... ketika kami menjalankannya, kami mendapatkan:
>>> Complex( float('inf') , 0j ) * 1
result: (inf + nanj)
Python memahami ini *1
sebagai bilangan kompleks dan bukan norma 1
sehingga ia menafsirkan sebagai *(1+0j)
dan kesalahan muncul ketika kita mencoba melakukan inf * 0j = nanj
sebagaiinf*0
tidak dapat diselesaikan.
Apa yang sebenarnya ingin Anda lakukan (dengan asumsi 1 adalah norma 1):
Ingatlah bahwa jika z = x + iy
bilangan kompleks dengan bagian nyata x dan bagian imajiner y, konjugasi kompleks dari z
didefinisikan sebagai z* = x − iy
, dan nilai absolut, juga disebut the norm of z
didefinisikan sebagai:
Dengan asumsi 1
norma 1
kita harus melakukan sesuatu seperti:
>>> c_num = complex(float('inf'),0)
>>> value = 1
>>> realPart=(c_num.real)*value
>>> imagPart=(c_num.imag)*value
>>> complex(realPart,imagPart)
result: (inf+0j)
tidak terlalu intuitif, saya tahu ... tetapi terkadang bahasa pengkodean didefinisikan dengan cara yang berbeda dari apa yang kita gunakan sehari-hari.