Mengapa ilmuwan komputasi perlu mengimplementasikan versi mereka sendiri dari std :: complex?
14
Banyak pustaka C ++ yang lebih terkenal dalam ilmu komputasi seperti Eigen , Trilinos , dan deal.II menggunakan objek pustaka header template C ++ standar std::complex<>,, untuk mewakili angka floating-point yang kompleks.
Dalam jawaban Jack Poulson untuk pertanyaan tentang konstruktor default, ia menunjukkan bahwa ia memiliki implementasinya sendiri std::complexdi Elemental "karena sejumlah alasan". Apa alasannya? Apa kelebihan dan kekurangan dari pendekatan ini?
Saya percaya diskusi ini telah muncul beberapa kali dalam daftar PETSc. Alasan utama saya adalah:
Standar C ++ menyatakan bahwa std :: complex hanya didefinisikan untuk tipe data float, double, dan long double. Dengan demikian itu tidak dapat digunakan untuk tipe data lain, seperti quad-precision.
Standar tidak memberikan jaminan tentang stabilitas aritmatika kompleks.
Standar tidak membuat jaminan bahwa data dalam std :: complex disimpan sebagai komponen nyata diikuti oleh komponen imajiner. Ini sangat penting untuk antarmuka dengan perpustakaan eksternal, seperti BLAS dan LAPACK. Memang benar untuk semua implementasi utama, tetapi saya lebih memilih untuk bisa memastikannya.
Saya lebih suka bisa secara langsung memanipulasi komponen nyata dan imajiner. std :: complex membuat ini sulit.
Saya ingin akhirnya memiliki versi yang lebih umum yang hanya membutuhkan datatype sebagai cincin daripada membutuhkan bidang. Ini akan mencakup bilangan bulat Gaussian.
Poin 3 telah dibahas dalam C ++ 11. 26.4.4 menyatakan bahwa jika zmerupakan ekspresi nilai dari tipe cvstd::complex<T> maka reinterpret_cast<cv T(&)[2]>(z)dan reinterpret_cast<cv T(&)[2]>(z)[0]harus menunjuk bagian sebenarnya z, dan reinterpret_cast<cv T(&)[2]>(z)[1]harus menunjuk bagian imajiner dari z. Susunan bilangan kompleks juga dibahas.
James Custer
3
@JamesCuster: Saya semua akhirnya beralih ke C ++ 11, tetapi kode ilmiah yang ingin tetap portabel untuk arsitektur semi-eksotis mungkin perlu menunggu setidaknya dua hingga tiga tahun lagi untuk melakukannya. Juga, C ++ 11 sayangnya hanya membahas sebagian dari masalah.
Jack Poulson
Saya mengerti, saya hanya membuangnya di sana kalau-kalau seseorang melihat pertanyaan ini di masa depan.
James Custer
2
Yah, saya pikir ini adalah alasan untuk mengatakan Anda harus menunggu sampai kompiler mendukung C ++ 11. Persyaratan eksplisit dimasukkan ke dalam standar baru karena semua implementasi yang ada sudah mendukungnya. Saya tidak bisa memikirkan kasus di mana tidak aman untuk mengasumsikan tata letak khusus ini di kompiler / pustaka yang sudah ada karena tidak masuk akal untuk mengimplementasikan std :: complex dengan cara lain.
Wolfgang Bangerth
1
@WolfgangBangerth: Itu lebih merupakan komentar umum tentang beralih ke C ++ 11. Either way, C ++ 11 tidak memperbaiki sebagian besar masalah dengan std :: complex.
Jack Poulson
7
Saya menggunakan std::complex<>dalam program saya, dan harus berjuang dengan flag compiler dan solusi untuk setiap compiler baru atau upgrade compiler. Saya akan mencoba menceritakan pertarungan ini dalam urutan kronologis:
std::norm| z|2| z|-ffast-math
Kompiler intel icc di linux (atau std::argtautan ) dikompilasi ke non-opt di bawah konfigurasi tertentu (kompatibilitas tautan dengan versi gcc tertentu). Masalahnya muncul kembali terlalu sering, jadi std::argharus diganti atan2(imag(),real()). Tapi itu terlalu mudah untuk melupakan ini ketika menulis kode baru.
Jenis std::complexmenggunakan konvensi panggilan yang berbeda (= ABI) dari jenis kompleks built-in C99, dan tipe kompleks Fortran built-in untuk versi gcc yang lebih baru.
The -ffast-mathberinteraksi bendera kompilasi dengan penanganan floating point pengecualian dalam cara yang tak terduga. Apa yang terjadi adalah bahwa kompiler menarik divisi keluar dari loop, sehingga menyebabkan division by zeropengecualian saat runtime. Pengecualian ini tidak akan pernah terjadi di dalam loop, karena pembagian yang sesuai tidak terjadi karena logika di sekitarnya. Yang itu benar-benar buruk, karena itu adalah perpustakaan yang dikompilasi secara terpisah dari program yang menggunakan pengecualian floating point menyerahkan (menggunakan bendera kompilasi yang berbeda) dan mengalami masalah ini (tim yang sesuai duduk di bagian yang berbeda di dunia, jadi masalah ini benar-benar menyebabkan masalah). Ini diselesaikan dengan melakukan optimasi yang digunakan oleh kompiler dengan tangan dengan lebih hati-hati.
Perpustakaan menjadi bagian dari program dan tidak lagi menggunakan -ffast-mathflag kompilasi. Setelah upgrade ke versi gcc yang lebih baru, kinerja turun dengan faktor yang sangat besar. Saya belum menyelidiki masalah ini secara detail, tapi aku takut hal itu berkaitan dengan C99 Lampiran G . Saya harus mengakui bahwa saya benar-benar bingung dengan definisi perkalian yang aneh untuk bilangan kompleks ini, dan bahkan ada versi yang berbeda dari ini dengan klaim bahwa versi lain salah arah. Saya harap -fcx-limited-rangeflag kompilasi akan menyelesaikan masalah, karena sepertinya ada masalah lain yang berkaitan dengan -ffast-mathuntuk versi gcc yang lebih baru ini.
The -ffast-mathflag kompilasi membuat perilaku NaNbenar-benar tak terduga untuk versi yang lebih baru dari gcc (bahkan isnanterpengaruh). Satu-satunya solusi tampaknya untuk menghindari terjadinya NaNdalam program, yang mengalahkan tujuan keberadaan NaN.
Sekarang Anda dapat bertanya apakah saya berencana untuk meninggalkan tipe kompleks bawaan dan std::complexuntuk alasan ini. Saya akan tetap menggunakan tipe bawaan, selama saya tetap menggunakan C ++. Dalam kasus C ++ harus menjadi benar-benar tidak dapat digunakan untuk komputasi ilmiah, saya lebih suka mempertimbangkan untuk beralih ke bahasa yang lebih memperhatikan masalah yang relevan dengan komputasi ilmiah.
Sepertinya ketakutan saya yang terkait dengan C99 Annex G telah menjadi kenyataan, dan -fcx-limited-range sekarang semacam diperlukan untuk kecepatan komputasi yang layak ketika mengalikan bilangan kompleks. Setidaknya itulah yang saya dapatkan dari kisah perang baru-baru ini: medium.com/@smcallis_71148/…
z
merupakan ekspresi nilai dari tipe cvstd::complex<T>
makareinterpret_cast<cv T(&)[2]>(z)
danreinterpret_cast<cv T(&)[2]>(z)[0]
harus menunjuk bagian sebenarnyaz
, danreinterpret_cast<cv T(&)[2]>(z)[1]
harus menunjuk bagian imajiner dariz
. Susunan bilangan kompleks juga dibahas.Saya menggunakan
std::complex<>
dalam program saya, dan harus berjuang dengan flag compiler dan solusi untuk setiap compiler baru atau upgrade compiler. Saya akan mencoba menceritakan pertarungan ini dalam urutan kronologis:std::norm
-ffast-math
std::arg
tautan ) dikompilasi ke non-opt di bawah konfigurasi tertentu (kompatibilitas tautan dengan versi gcc tertentu). Masalahnya muncul kembali terlalu sering, jadistd::arg
harus digantiatan2(imag(),real())
. Tapi itu terlalu mudah untuk melupakan ini ketika menulis kode baru.std::complex
menggunakan konvensi panggilan yang berbeda (= ABI) dari jenis kompleks built-in C99, dan tipe kompleks Fortran built-in untuk versi gcc yang lebih baru.-ffast-math
berinteraksi bendera kompilasi dengan penanganan floating point pengecualian dalam cara yang tak terduga. Apa yang terjadi adalah bahwa kompiler menarik divisi keluar dari loop, sehingga menyebabkandivision by zero
pengecualian saat runtime. Pengecualian ini tidak akan pernah terjadi di dalam loop, karena pembagian yang sesuai tidak terjadi karena logika di sekitarnya. Yang itu benar-benar buruk, karena itu adalah perpustakaan yang dikompilasi secara terpisah dari program yang menggunakan pengecualian floating point menyerahkan (menggunakan bendera kompilasi yang berbeda) dan mengalami masalah ini (tim yang sesuai duduk di bagian yang berbeda di dunia, jadi masalah ini benar-benar menyebabkan masalah). Ini diselesaikan dengan melakukan optimasi yang digunakan oleh kompiler dengan tangan dengan lebih hati-hati.-ffast-math
flag kompilasi. Setelah upgrade ke versi gcc yang lebih baru, kinerja turun dengan faktor yang sangat besar. Saya belum menyelidiki masalah ini secara detail, tapi aku takut hal itu berkaitan dengan C99 Lampiran G . Saya harus mengakui bahwa saya benar-benar bingung dengan definisi perkalian yang aneh untuk bilangan kompleks ini, dan bahkan ada versi yang berbeda dari ini dengan klaim bahwa versi lain salah arah. Saya harap-fcx-limited-range
flag kompilasi akan menyelesaikan masalah, karena sepertinya ada masalah lain yang berkaitan dengan-ffast-math
untuk versi gcc yang lebih baru ini.-ffast-math
flag kompilasi membuat perilakuNaN
benar-benar tak terduga untuk versi yang lebih baru dari gcc (bahkanisnan
terpengaruh). Satu-satunya solusi tampaknya untuk menghindari terjadinyaNaN
dalam program, yang mengalahkan tujuan keberadaanNaN
.Sekarang Anda dapat bertanya apakah saya berencana untuk meninggalkan tipe kompleks bawaan dan
std::complex
untuk alasan ini. Saya akan tetap menggunakan tipe bawaan, selama saya tetap menggunakan C ++. Dalam kasus C ++ harus menjadi benar-benar tidak dapat digunakan untuk komputasi ilmiah, saya lebih suka mempertimbangkan untuk beralih ke bahasa yang lebih memperhatikan masalah yang relevan dengan komputasi ilmiah.sumber