nilai ganda minimum dalam C / C ++

92

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 .

Akan
sumber
4
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_MAX di ANSI C , yang didefinisikan di float.h.

dfa
sumber
ini tampaknya yang paling standar dan portabel
Akankah
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
@j_random_hacker: lihat jawaban fortran 'di bawah'.
JohnTortugo
3
@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.

Dan kemudian adalah cara yang keren:

double f;
(*((long long*)&f))= ~(1LL<<52);
fortran
sumber
6
+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).
Christophe
44

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();
rubenvb.dll
sumber
Bukankah min()fungsi tersedia sebelum C ++ 11? Atau apakah itu nilai yang berbeda dari -max()? en.cppreference.com/w/cpp/types/numeric_limits
Alexis Wilke
5
@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
Ciprian Tomoiagă
33

Coba ini:

-1 * numeric_limits<double>::max()

Referensi: numeric_limits

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.

Andrew Hare
sumber
1
Kenapa tidak -numeric_limits<double>::max()?
k06a
4
@ 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.

Christoph
sumber
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.

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:

masukkan deskripsi gambar di sini

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 * /

Christophe
sumber
7
- std::numeric_limits<double>::max()

seharusnya bekerja dengan baik

Batas numerik

MadH
sumber
1

Pertanyaan asli menyangkut ketidakterbatasan. Jadi, mengapa tidak digunakan

#define Infinity  ((double)(42 / 0.0))

menurut definisi IEEE? Anda tentu saja dapat meniadakannya.

Norbert
sumber
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);

// 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;
chux - Kembalikan Monica
sumber
-1

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.

cmaster - kembalikan monica
sumber
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.
cmaster