Kapan saya menggunakan fabs dan kapan cukup menggunakan std :: abs?

100

Saya berasumsi bahwa absdan fabsberperilaku berbeda saat menggunakan math.h. Tetapi ketika saya menggunakan just cmathand std::abs, apakah saya harus menggunakan std::fabsatau fabs? Atau bukankah ini didefinisikan?

matematika
sumber

Jawaban:

124

Di C ++, itu selalu cukup untuk digunakan std::abs; itu kelebihan beban untuk semua tipe numerik.

Di C, abshanya bekerja pada integer, dan Anda membutuhkan fabsnilai floating point. Ini tersedia dalam C ++ (bersama dengan semua pustaka C), tetapi tidak perlu menggunakannya.

Mike Seymour
sumber
Apakah kasus ini terjadi di setiap platform? Esp. Windows dan Mac OS X? Atau setidaknya dalam standar C ++?
matematika
3
@brubelsabs: ya. Tidak diperlukan fungsi fabs terpisah dalam C ++ karena C ++ memiliki kelebihan beban (abs dapat didefinisikan untuk berbagai jenis dan ini dalam C ++). Itu juga dijamin oleh standar. Tentu saja jika Anda mencari-cari kompiler usang yang berusia lebih dari 10 tahun, Anda mungkin menemukan salah satu yang tidak mendukungnya.
stinky472
1
Ada dalam C ++ Standard, sehingga kasus pada setiap platform dengan compiler yang layak, termasuk Windows dan Mac OS X. Klausul 26.5 mengatakan bahwa, selain intversi dari perpustakaan C, ada overload untuk long, float, doubledan long double. Klausul 26.2.7 juga mendefinisikan kelebihan beban complex.
Mike Seymour
6
Jika Anda lupa std::dan hanya menggunakan abs, kode Anda akan berfungsi seperti yang diharapkan di windows tetapi akan menggunakan intversi di linux, yang bisa sangat sulit untuk di-debug.
Adversus
" semua tipe numerik" [butuh rujukan]. Saya bisa melihat int, long, long long, std :: intmax_t, float, double, long double. Tidak ada versi pendek atau char (atau versi unsigned) yang dapat saya lihat.
pengguna673679
23

Masih boleh digunakan fabsuntuk doubledan floatargumen. Saya lebih suka ini karena ini memastikan bahwa jika saya secara tidak sengaja std::melepas abs, bahwa perilaku tetap sama untuk input floating point.

Saya hanya menghabiskan 10 menit men-debug masalah ini, karena kesalahan saya sendiri dalam menggunakan, absbukan std::abs. Saya berasumsi bahwa using namespace std;akan menyimpulkan std::abstetapi tidak, dan sebagai gantinya menggunakan versi C.

Bagaimanapun, saya percaya itu baik untuk digunakan fabsdaripada absuntuk input floating-point sebagai cara untuk mendokumentasikan niat Anda dengan jelas.

Alan Turing
sumber
2
Itu aneh. Panggilan Anda seharusnya ambigu (dan karenanya merupakan kesalahan) bukan?
Nick
Bukankah seharusnya Anda menggunakan fabsf untuk float? Jadi menurut saya mereka tidak identik.
Nick
Waspadai Android NDK g ++, ini juga menyerahkan ke fungsi c abs () alih-alih std :: abs (). Dalam Visual Studio c ++ compiler abs selalu menunjuk ke std :: abs () sekalipun.
southerton
@ Nick, saya pikir saya setuju dengan Anda: Saya tampaknya tidak mendapatkan perilaku Alan Turing yaitu bagi saya kelebihan beban std::abstampaknya selalu dipanggil (dan bukan versi C abs) saat menelepon absselama using namespace std;dijelaskan di awal. Saya tidak tahu apakah ini khusus kompiler.
MaviPranav
@Nick bukan kesalahan karena ada nama fungsi yang cocok. Ini adalah implementasi yang ditentukan mana yang akan dipilih.
Pato Sandaña
11

Ada satu alasan lagi untuk merekomendasikan std::fabsinput floating-point secara eksplisit.

Jika Anda lupa menyertakan <cmath>, Anda std::abs(my_float_num)bisa jadi std::abs(int)bukan std::abs(float). Sulit untuk diperhatikan.

Kenichi Hidai
sumber
1

"abs" dan "fabs" hanya identik untuk tipe float C ++, jika dapat diterjemahkan tanpa pesan overload yang ambigu.

Saya menggunakan g ++ (g ++ - 7). Bersama dengan penggunaan template dan terutama saat menggunakan mpreal, ada kasus dengan pesan "ambiguous overload" yang keras - abs(static_cast<T>(x))tidak selalu menyelesaikannya. Ketika abs tidak ambigu, ada kemungkinan fabs bekerja seperti yang diharapkan. Untuk sqrt saya tidak menemukan jalan keluar yang sederhana.

Sejak berminggu-minggu saya berjuang keras di C ++ "bukan masalah yang ada". Saya memperbarui program C ++ lama ke C ++ 14 untuk penggunaan template yang lebih banyak dan lebih baik daripada sebelumnya. Seringkali parameter template yang sama dapat berupa tipe float atau kompleks standar atau tipe kelas apa pun. Mengapa, long double bertindak agak lebih masuk akal daripada tipe lainnya. Semua berfungsi, dan saya telah memasukkan mpreal sebelumnya. Kemudian saya mengatur tipe float default saya ke mpreal dan mengalami banjir kesalahan sintaks. Itu memberi ribuan kelebihan yang ambigu misalnya untuk abs dan sqrt, menangis untuk solusi yang berbeda. Beberapa membutuhkan fungsi bantuan yang kelebihan beban, tetapi di luar templat. Harus mengganti seribu penggunaan 0,0L dan 1,0L secara individual dengan tipe konstan yang tepat menggunakan Nol atau Satu atau type_cast - definisi konversi otomatis tidak mungkin karena ambiguitas.

Hingga Mei saya menemukan adanya konversi implisit sangat bagus. Tetapi jauh lebih sederhana itu akan menjadi tanpa apapun, dan memiliki konstanta tipe simpan dengan type_casts eksplisit yang aman ke tipe konstan standar lainnya.

BS3
sumber