Apakah ada cara standar dan / atau portabel untuk merepresentasikan nilai negatif terkecil (misalnya menggunakan tak terhingga negatif) dalam program C (++)?
DBL_MIN dalam float.h adalah bilangan positif terkecil .
Saya akan memilih -DBL_MAX, tapi saya yakin ada beberapa alasan teknis mengapa tidak demikian :-)
4
@Neil, tidak ada tidak, ini tidak seperti 2 komplemen bilangan bulat
fortran
Saya belum melihat apa pun dalam standar yang mengatakan bahwa kisaran tipe floating point harus simetris sekitar nol. Tetapi konstanta dalam limit.h dan <limits> menunjukkan bahwa standar C dan C ++ sama-sama diharapkan.
Steve Jessop
4
Sebenarnya DBL_MIN dalam float.h adalah bilangan normalisasi positif terkecil . Ada angka yang bahkan lebih kecil.
fdermishin
1
@fortran: IEEE 754 FP menggunakan sedikit tanda, dan tentunya sebagian besar perangkat keras FP saat ini adalah IEEE 754. Tetapi C dan C ++ mendukung perangkat keras non-IEEE 754 FP, jadi pertanyaannya terbuka apakah bahasa tersebut menjamin bahwa -DBL_MAX harus sama dengan nilai minimum yang dapat diwakili.
j_random_hacker
Jawaban:
135
-DBL_MAXdi ANSI C , yang didefinisikan di float.h.
Berikut penjelasan untuk -1 saya: siapa atau apa yang mengatakan bahwa -DBL_MAX dijamin oleh bahasa C atau C ++ dapat diwakili, apalagi nilai minimum yang dapat diwakili? Fakta bahwa sebagian besar perangkat keras FP sesuai dengan IEEE 754, dan menggunakan representasi ini, tidak berarti -DBL_MAX dijamin bekerja pada platform C yang sesuai standar.
@j_random_hacker Itu poin yang sangat bagus, tetapi standar C -DBL_MAXharus benar-benar dapat direpresentasikan, jadi jika perangkat keras FP tidak mampu melakukannya, implementasinya harus mengatasinya. Lihat model floating-point di 5.2.4.2.2 Karakteristik tipe mengambang <float.h> p2 dari C99 (mungkin telah dipindahkan ke tempat lain sejak saat itu).
2
@j_random_hacker Ya, tetapi p2 menetapkan e_min dan e_max tidak bergantung pada bit tanda, jadi DBL_MAXpersis (1 - b ^ −p) b ^ e_max, yang dapat direpresentasikan secara tepat, nilai hingga paling negatif persis - (1 - b ^ −p) b ^ e_max, dan karena itu terjadi tepat -DBL_MAX, meniadakan DBL_MAXjuga tidak dapat menyebabkan kesalahan pembulatan.
70
Angka floating point (IEEE 754) adalah simetris, jadi jika Anda dapat mewakili nilai terbesar ( DBL_MAXatau numeric_limits<double>::max()), tambahkan saja tanda minus.
+1 Untuk menunjukkan simetri bilangan floating point :)
Andrew Hare
4
Bagaimana dengan implementasi C / C ++ yang tidak menggunakan float IEEE 754?
Steve Jessop
1
Panduan gcc untuk -ffast-math mengatakan "Set -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans dan -fcx-limited- range Opsi ini tidak diaktifkan oleh opsi -O karena dapat menghasilkan keluaran yang salah untuk program yang bergantung pada implementasi yang tepat dari aturan / spesifikasi IEEE atau ISO untuk fungsi matematika. Namun, ini dapat menghasilkan kode yang lebih cepat untuk program yang melakukan tidak memerlukan jaminan spesifikasi ini. " Matematika cepat adalah pengaturan umum, dan Intel ICC misalnya default untuk itu. Secara keseluruhan, tidak yakin apa artinya ini bagi saya :-)
Akankah
4
Artinya implementasi tidak menggunakan aritmatika IEEE 754, tetapi untuk adilnya opsi tersebut masih menggunakan representasi IEEE. Anda mungkin menemukan beberapa pustaka emulasi menggunakan representasi non-IEEE, karena tidak semua prosesor memiliki format float asli (meskipun mereka dapat menerbitkan C ABI yang menyertakan format, sesuai dengan pustaka emulasi yang disediakan oleh pabrikan). Karenanya tidak semua kompiler dapat menggunakan satu. Tergantung apa yang Anda maksud ketika Anda meminta "standar dan / atau portabel", ada portabel pada prinsipnya dan dalam praktiknya portabel.
Steve Jessop
3
Apa yang Anda katakan benar untuk IEEE 754, tetapi standarnya tidak memerlukan penggunaan pengkodean ini (seperti yang ditunjukkan @SteveJessop, portabel dalam praktiknya tidak sama dengan portabel pada prinsipnya).
@Alexis: jika Anda melihat pada tiga baris terendah dalam tabel pada halaman yang Anda tautkan, Anda akan melihat bahwa minAnda mendapatkan nilai positif terkecil dalam besaran, dan lowestnilai negatif terbesar dalam besaran. Ya, itu mengerikan. Selamat datang di dunia pustaka standar C ++ yang brilian :-P.
rubenvb
untuk C itu didefinisikan dalam float.h. limits.hadalah untuk bilangan bulat
Kelas ini dikhususkan untuk setiap tipe dasar, dengan anggotanya yang kembali atau disetel ke nilai berbeda yang menentukan properti yang dimiliki tipe dalam platform spesifik tempat ia dikompilasi.
@ k06a memiliki negasi yang diwakili oleh satu karakter dalam ekspresi yang begitu panjang, di mana string bahkan mengatakan "max", pasti akan membuat seseorang cepat atau lambat. Entah itu disimpan dalam variabel deskriptif, atau gunakan -1 * ...untuk membuatnya sedikit lebih jelas.
Filip Haglund
20
Apakah Anda mencari infinity aktual atau nilai terbatas minimal? Jika bekas, gunakan
-numeric_limits<double>::infinity()
yang hanya berfungsi jika
numeric_limits<double>::has_infinity
Jika tidak, Anda harus menggunakan
numeric_limits<double>::lowest()
yang diperkenalkan di C ++ 11.
Jika lowest()tidak tersedia, Anda dapat kembali ke
-numeric_limits<double>::max()
yang mungkin berbeda dari lowest()prinsipnya, tetapi biasanya tidak dalam praktiknya.
1 untuk perbedaan antara nilai hingga dan tak terbatas! Tetapi standar tidak menjamin pengkodean titik mengambang simetris. Jadi -numeric_limits<double>::max()bahkan jika itu berhasil dalam prakteknya tidak sepenuhnya portabel dalam teori.
Christophe
@Christophe: [x] diperbaiki
Christoph
10
Solusi C ++ yang benar-benar portabel
Mulai dari C ++ 11 Anda dapat menggunakan numeric_limits<double>::lowest(). Menurut standar, ini mengembalikan persis apa yang Anda cari:
Nilai hingga x sedemikian sehingga tidak ada nilai hingga lainnya y di mana y < x.
Berarti untuk semua spesialisasi di dalamnya is_bounded != false.
Ada banyak jawaban yang muncul -std::numeric_limits<double>::max().
Untungnya, mereka akan bekerja dengan baik di sebagian besar kasus. Skema pengkodean titik mengambang menguraikan angka dalam mantissa dan eksponen dan kebanyakan dari mereka (misalnya IEEE-754 yang populer ) menggunakan bit tanda yang berbeda, yang bukan milik mantissa. Ini memungkinkan untuk mengubah positif terbesar menjadi negatif terkecil hanya dengan membalik tandanya:
Mengapa ini tidak portabel?
Standar tersebut tidak memberlakukan standar floating point.
Saya setuju bahwa argumen saya sedikit teoretis, tetapi anggaplah beberapa pembuat kompilator yang sangat baik akan menggunakan skema pengkodean revolusioner dengan mantissa yang dikodekan dalam beberapa variasi pelengkap dua . Pengkodean komplemen Two tidak simetris. misalnya untuk karakter 8 bit bertanda positif maksimum 127, tetapi negatif minimum adalah -128. Jadi kita bisa membayangkan beberapa pengkodean floating point menunjukkan perilaku asimetris yang serupa.
Saya tidak mengetahui skema pengkodean seperti itu, tetapi intinya adalah bahwa standar tidak menjamin bahwa tanda membalik menghasilkan hasil yang diinginkan . Jadi jawaban populer ini (maaf guys!) Tidak dapat dianggap sebagai solusi standar yang sepenuhnya portabel! / * setidaknya tidak jika Anda tidak menegaskan bahwa numeric_limits<double>::is_iec559itu benar * /
Ide bagus ! Dan itu berhasil . Tetapi hanya jikanumeric_limits<double>::has_infinity && ! numeric_limits<double>::traps
Christophe
1
Apakah ada cara standar dan / atau portabel untuk merepresentasikan nilai negatif terkecil (misalnya menggunakan tak terhingga negatif) dalam program C (++)?
Pendekatan C.
Banyak implementasi mendukung +/- tak terhingga, jadi nilai yang paling negatif doubleadalah -INFINITY.
#include<math.h>double most_negative = -INFINITY;
Apakah ada cara standar dan / atau portabel ....?
Sekarang kita juga perlu mempertimbangkan kasus lain:
Tidak ada infinities
Sederhana -DBL_MAX.
Hanya tak terhingga yang tak bertanda tangan .
Saya berharap dalam kasus ini, OP lebih suka -DBL_MAX.
Nilai de-normal lebih besar dari DBL_MAX.
Ini adalah kasus yang tidak biasa, kemungkinan besar di luar perhatian OP. Ketika doubledikodekan sebagai sepasang titik mengambang untuk mencapai kisaran / presesi yang diinginkan, (lihat ganda-ganda ) terdapat normal maksimum doubledan mungkin yang lebih besar dari normal . Saya telah melihat perdebatan jika DBL_MAXharus mengacu pada normal terbesar , dari yang terbesar dari keduanya.
Untungnya pendekatan berpasangan ini biasanya menyertakan -infinity, sehingga nilai paling negatif tetap ada -INFINITY.
Untuk portabilitas lebih, kode dapat menyusuri rute
// HUGE_VAL is designed to be infinity or DBL_MAX (when infinites are not implemented)// .. yet is problematic with unsigned infinity.double most_negative1 = -HUGE_VAL;
// Fairly portable, unless system does not understand "INF"double most_negative2 = strtod("-INF", (char **) NULL);
// Pragmaticdouble most_negative3 = strtod("-1.0e999999999", (char **) NULL);
// Somewhat time-consumingdouble most_negative4 = pow(-DBL_MAX, 0xFFFF/* odd value */);
// My suggestiondouble most_negative5 = (-DBL_MAX)*DBL_MAX;
Jika Anda tidak mengaktifkan pengecualian float (yang seharusnya tidak Anda imho), Anda cukup mengatakan:
double neg_inf = -1/0.0;
Ini menghasilkan ketidakterbatasan negatif. Jika Anda membutuhkan pelampung, Anda bisa melemparkan hasilnya
float neg_inf = (float)-1/0.0;
atau gunakan aritmatika presisi tunggal
float neg_inf = -1.0f/0.0f;
Hasilnya selalu sama, persis ada satu representasi tak terhingga negatif dalam presisi tunggal dan ganda, dan keduanya saling mengubah seperti yang Anda harapkan.
Mengapa Anda melakukan ini daripada hanya menulis-INFINITY
MM
Juga, ketidakterbatasan mungkin ada atau mungkin tidak ada, dan jika itu memang ada maka positif dan negatif mungkin tidak dapat dibedakan (dalam Standar C).
MM
Dalam banyak kompiler dan / atau arsitektur, kode C / C ++ Anda akan memperlambat banyak dari Anda yang menyebarkan nilai tak terhingga dan NaN.
markgalassi
@markgalassi Harap perhatikan lebih dekat: Anda akan melihat bahwa neg_infdiinisialisasi ke nilai konstan . Kompiler akan menghitung infnilainya. Dan saat Anda menggunakannya sebagai nilai null untuk menghitung maks, iterasi pertama biasanya akan menimpanya dengan nilai yang lebih besar. Yaitu kinerja hampir tidak menjadi masalah. Dan OP bertanya secara khusus tentang "misalnya menggunakan tak terhingga negatif", dan -infmemang satu-satunya jawaban yang benar untuk ini. Anda tidak menyukai jawaban yang benar dan berguna.
Jawaban:
-DBL_MAX
di ANSI C , yang didefinisikan di float.h.sumber
-DBL_MAX
harus benar-benar dapat direpresentasikan, jadi jika perangkat keras FP tidak mampu melakukannya, implementasinya harus mengatasinya. Lihat model floating-point di 5.2.4.2.2 Karakteristik tipe mengambang <float.h> p2 dari C99 (mungkin telah dipindahkan ke tempat lain sejak saat itu).DBL_MAX
persis (1 - b ^ −p) b ^ e_max, yang dapat direpresentasikan secara tepat, nilai hingga paling negatif persis - (1 - b ^ −p) b ^ e_max, dan karena itu terjadi tepat-DBL_MAX
, meniadakanDBL_MAX
juga tidak dapat menyebabkan kesalahan pembulatan.Angka floating point (IEEE 754) adalah simetris, jadi jika Anda dapat mewakili nilai terbesar (
DBL_MAX
ataunumeric_limits<double>::max()
), tambahkan saja tanda minus.Dan kemudian adalah cara yang keren:
double f; (*((long long*)&f))= ~(1LL<<52);
sumber
Di C, gunakan
#include <float.h> const double lowest_double = -DBL_MAX;
Di C ++ pra-11, gunakan
#include <limits> const double lowest_double = -std::numeric_limits<double>::max();
Di C ++ 11 dan seterusnya, gunakan
#include <limits> constexpr double lowest_double = std::numeric_limits<double>::lowest();
sumber
min()
fungsi tersedia sebelum C ++ 11? Atau apakah itu nilai yang berbeda dari-max()
? en.cppreference.com/w/cpp/types/numeric_limitsmin
Anda mendapatkan nilai positif terkecil dalam besaran, danlowest
nilai negatif terbesar dalam besaran. Ya, itu mengerikan. Selamat datang di dunia pustaka standar C ++ yang brilian:-P
.float.h
.limits.h
adalah untuk bilangan bulatCoba ini:
-1 * numeric_limits<double>::max()
Referensi:
numeric_limits
sumber
-numeric_limits<double>::max()
?-1 * ...
untuk membuatnya sedikit lebih jelas.Apakah Anda mencari infinity aktual atau nilai terbatas minimal? Jika bekas, gunakan
-numeric_limits<double>::infinity()
yang hanya berfungsi jika
numeric_limits<double>::has_infinity
Jika tidak, Anda harus menggunakan
numeric_limits<double>::lowest()
yang diperkenalkan di C ++ 11.
Jika
lowest()
tidak tersedia, Anda dapat kembali ke-numeric_limits<double>::max()
yang mungkin berbeda dari
lowest()
prinsipnya, tetapi biasanya tidak dalam praktiknya.sumber
-numeric_limits<double>::max()
bahkan jika itu berhasil dalam prakteknya tidak sepenuhnya portabel dalam teori.Solusi C ++ yang benar-benar portabel
Mulai dari C ++ 11 Anda dapat menggunakan
numeric_limits<double>::lowest()
. Menurut standar, ini mengembalikan persis apa yang Anda cari:Demo online
Banyak jawaban C ++ non portabel di sini!
Ada banyak jawaban yang muncul
-std::numeric_limits<double>::max()
.Untungnya, mereka akan bekerja dengan baik di sebagian besar kasus. Skema pengkodean titik mengambang menguraikan angka dalam mantissa dan eksponen dan kebanyakan dari mereka (misalnya IEEE-754 yang populer ) menggunakan bit tanda yang berbeda, yang bukan milik mantissa. Ini memungkinkan untuk mengubah positif terbesar menjadi negatif terkecil hanya dengan membalik tandanya:
Mengapa ini tidak portabel?
Standar tersebut tidak memberlakukan standar floating point.
Saya setuju bahwa argumen saya sedikit teoretis, tetapi anggaplah beberapa pembuat kompilator yang sangat baik akan menggunakan skema pengkodean revolusioner dengan mantissa yang dikodekan dalam beberapa variasi pelengkap dua . Pengkodean komplemen Two tidak simetris. misalnya untuk karakter 8 bit bertanda positif maksimum 127, tetapi negatif minimum adalah -128. Jadi kita bisa membayangkan beberapa pengkodean floating point menunjukkan perilaku asimetris yang serupa.
Saya tidak mengetahui skema pengkodean seperti itu, tetapi intinya adalah bahwa standar tidak menjamin bahwa tanda membalik menghasilkan hasil yang diinginkan . Jadi jawaban populer ini (maaf guys!) Tidak dapat dianggap sebagai solusi standar yang sepenuhnya portabel! / * setidaknya tidak jika Anda tidak menegaskan bahwa
numeric_limits<double>::is_iec559
itu benar * /sumber
- std::numeric_limits<double>::max()
seharusnya bekerja dengan baik
Batas numerik
sumber
Pertanyaan asli menyangkut ketidakterbatasan. Jadi, mengapa tidak digunakan
#define Infinity ((double)(42 / 0.0))
menurut definisi IEEE? Anda tentu saja dapat meniadakannya.
sumber
numeric_limits<double>::has_infinity && ! numeric_limits<double>::traps
Pendekatan C.
Banyak implementasi mendukung +/- tak terhingga, jadi nilai yang paling negatif
double
adalah-INFINITY
.#include <math.h> double most_negative = -INFINITY;
Sekarang kita juga perlu mempertimbangkan kasus lain:
Sederhana
-DBL_MAX
.Saya berharap dalam kasus ini, OP lebih suka
-DBL_MAX
.DBL_MAX
.Ini adalah kasus yang tidak biasa, kemungkinan besar di luar perhatian OP. Ketika
double
dikodekan sebagai sepasang titik mengambang untuk mencapai kisaran / presesi yang diinginkan, (lihat ganda-ganda ) terdapat normal maksimumdouble
dan mungkin yang lebih besar dari normal . Saya telah melihat perdebatan jikaDBL_MAX
harus mengacu pada normal terbesar , dari yang terbesar dari keduanya.Untungnya pendekatan berpasangan ini biasanya menyertakan -infinity, sehingga nilai paling negatif tetap ada
-INFINITY
.Untuk portabilitas lebih, kode dapat menyusuri rute
// HUGE_VAL is designed to be infinity or DBL_MAX (when infinites are not implemented) // .. yet is problematic with unsigned infinity. double most_negative1 = -HUGE_VAL; // Fairly portable, unless system does not understand "INF" double most_negative2 = strtod("-INF", (char **) NULL); // Pragmatic double most_negative3 = strtod("-1.0e999999999", (char **) NULL); // Somewhat time-consuming double most_negative4 = pow(-DBL_MAX, 0xFFFF /* odd value */); // My suggestion double most_negative5 = (-DBL_MAX)*DBL_MAX;
sumber
Jika Anda tidak mengaktifkan pengecualian float (yang seharusnya tidak Anda imho), Anda cukup mengatakan:
double neg_inf = -1/0.0;
Ini menghasilkan ketidakterbatasan negatif. Jika Anda membutuhkan pelampung, Anda bisa melemparkan hasilnya
float neg_inf = (float)-1/0.0;
atau gunakan aritmatika presisi tunggal
float neg_inf = -1.0f/0.0f;
Hasilnya selalu sama, persis ada satu representasi tak terhingga negatif dalam presisi tunggal dan ganda, dan keduanya saling mengubah seperti yang Anda harapkan.
sumber
-INFINITY
neg_inf
diinisialisasi ke nilai konstan . Kompiler akan menghitunginf
nilainya. Dan saat Anda menggunakannya sebagai nilai null untuk menghitung maks, iterasi pertama biasanya akan menimpanya dengan nilai yang lebih besar. Yaitu kinerja hampir tidak menjadi masalah. Dan OP bertanya secara khusus tentang "misalnya menggunakan tak terhingga negatif", dan-inf
memang satu-satunya jawaban yang benar untuk ini. Anda tidak menyukai jawaban yang benar dan berguna.