C / C ++ 'da minimum çift değer


92

Bir C (++) programında en küçük negatif değeri temsil etmenin (örneğin negatif sonsuzluğu kullanmak için) standart ve / veya taşınabilir bir yolu var mı?

Float.h içindeki DBL_MIN, en küçük pozitif sayıdır.


4
Ben -DBL_MAX için gidersiniz ama bu kadar değil neden emin :-) bazı teknik neden yoktur ediyorum

4
@Neil, hayır öyle 2 Tamamlayıcı tamsayılar gibi orada değil değil
fortran

Henüz standartta kayan nokta türlerinin aralığının sıfır civarında simetrik olması gerektiğini söyleyen hiçbir şey görmedim. Ancak limits.h ve <limits> içindeki sabitler, hem C hem de C ++ standardının beklediğini düşündürür.
Steve Jessop

4
Aslında float.h içindeki DBL_MIN, en küçük pozitif normalleştirilmiş sayıdır. Daha da küçük sayılar var.
fdermishin

1
@fortran: IEEE 754 FP bir işaret biti kullanıyor ve bugünlerde çoğu FP donanımı IEEE 754'tür. Ancak C ve C ++, IEEE 754 FP olmayan donanımı destekler, bu nedenle dilin -DBL_MAX garantisini verip vermediği sorusu açıktır. temsil edilebilir minimum değere eşit olmalıdır.
j_random_hacker

Yanıtlar:


135

-DBL_MAX float.h içinde tanımlanan ANSI C'de .


Bu çoğu standart ve taşınabilir görünüyor
Will

İşte -1 için açıklama: -DBL_MAX'ın temsil edilebilir olması bir yana, C veya C ++ dili tarafından garanti edildiğini kim veya ne söylüyor? Çoğu FP donanımının IEEE 754 uyumlu olması ve bu gösterimi kullanması, -DBL_MAX'ın herhangi bir standart uyumlu C platformunda çalışacağı anlamına gelmez.
j_random_hacker

@j_random_hacker: fortran'ın 'aşağıdaki' cevabına bakın.
JohnTortugo

3
@j_random_hacker Bu çok iyi bir nokta, ancak C standardının -DBL_MAXtam olarak gösterilebilir olması gerekir, bu nedenle FP donanımı bunu yapamazsa, uygulama bunun etrafında çalışmalıdır. 5.2.4.2.2 C99'daki kayan tiplerin <float.h> p2 karakteristiklerindeki kayan nokta modeline bakın (o zamandan beri başka bir yere taşınmış olabilir).

2
@j_random_hacker Evet, ancak p2 e_min ve e_max'ın işaret bitinden bağımsız olduğunu belirtir, bu DBL_MAXnedenle tam olarak (1 - b ^ −p) b ^ e_max, tam olarak gösterilebilir, en negatif sonlu değer tam olarak - (1 - b ^ −p) b ^ e_max, ve bu tam olarak olduğu için -DBL_MAX, olumsuzlama DBL_MAXda herhangi bir yuvarlama hatası getiremez.

70

Kayan nokta numaraları (IEEE 754) simetriktir, bu nedenle en büyük değeri ( DBL_MAXveya numeric_limits<double>::max()) temsil edebiliyorsanız , başına bir eksi işareti ekleyin.

Ve sonra harika yol:

double f;
(*((long long*)&f))= ~(1LL<<52);

6
+1 Kayan noktalı sayıların simetrisine işaret ettiğin için :)
Andrew Hare

4
IEEE 754 kayan nokta kullanmayan C / C ++ uygulamaları ne olacak?
Steve Jessop

1
gcc'nin -ffast-math için el kitabında "-fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans-nans ve -fcx-limited" yazıyor range Bu seçenek herhangi bir -O seçeneği tarafından açılmaz çünkü matematik işlevler için IEEE veya ISO kurallarının / özelliklerinin tam olarak uygulanmasına bağlı olan programlar için yanlış çıktıya neden olabilir.Ancak, bunu yapan programlar için daha hızlı kod verebilir bu özelliklerin garantilerini gerektirmez. " Hızlı matematik yaygın bir ayardır ve örneğin Intel ICC bunu varsayılan olarak kullanır. Değil emin ne bu vasıta :-) benim için Sonuçta
Will

4
Bu, uygulamaların IEEE 754 aritmetiğini kullanmadığı anlamına gelir, ancak adil olmak gerekirse, bu seçenekler hala IEEE temsilini kullanır. Tüm işlemcilerin yerel kayan formatı olmadığından (üretici tarafından sağlanan öykünme kitaplıklarına karşılık gelen bir biçim içeren bir C ABI yayınlayabilmesine rağmen), IEEE dışı gösterimi kullanan bazı öykünme kitaplıkları bulabilirsiniz. Dolayısıyla tüm derleyiciler bir tane kullanamaz. "Standart ve / veya taşınabilir" dediğinizde ne demek istediğinize bağlı, prensipte taşınabilir ve pratikte taşınabilir var.
Steve Jessop

3
Söyledikleriniz IEEE 754 için doğrudur, ancak standart bu kodlamanın kullanılmasını gerektirmez (@SteveJessop'un işaret ettiği gibi, pratikte taşınabilirlik ilke olarak taşınabilir ile aynı değildir).
Christophe

44

C'de, kullanın

#include <float.h>

const double lowest_double = -DBL_MAX;

C ++ 11 öncesi sürümde

#include <limits>

const double lowest_double = -std::numeric_limits<double>::max();

C ++ 11 ve sonrasında, kullanın

#include <limits>

constexpr double lowest_double = std::numeric_limits<double>::lowest();

min()İşlev C ++ 11'den önce mevcut değil miydi ? Yoksa bundan farklı bir değer -max()mi? en.cppreference.com/w/cpp/types/numeric_limits
Alexis Wilke

5
@Alexis: Bağlandığınız sayfadaki tablodaki en düşük üç satıra bakarsanız, bunun minsize büyüklük olarak en küçük pozitif değeri ve büyüklük olarak lowesten büyük negatif değeri verdiğini görürsünüz . Evet, korkunç. C ++ standart kitaplığının parlak dünyasına hoş geldiniz :-P.
rubenvb

C için tanımlanmıştır float.h. limits.htamsayılar içindir
Ciprian Tomoiagă

33

Bunu dene:

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

Referans: numeric_limits

Bu sınıf, temel türlerin her biri için uzmanlaşmıştır, üyeleri, derlediği belirli platformda türün sahip olduğu özellikleri tanımlayan farklı değerlere geri döner veya ayarlanır.


1
Neden sadece değil -numeric_limits<double>::max()?
k06a

4
@ k06a, bu kadar uzun bir ifadede tek bir karakterle temsil edilen olumsuzluğa sahip olması, dizenin "max" bile olsa, er ya da geç birini alacağından emin olabilirsiniz. Ya tanımlayıcı bir değişkende saklanır ya -1 * ...da onu biraz daha netleştirmek için kullanılır.
Filip Haglund

20

Gerçek sonsuzluğu mu yoksa minimum sonlu değeri mi arıyorsunuz? İlki ise, kullanın

-numeric_limits<double>::infinity()

sadece eğer işe yarar

numeric_limits<double>::has_infinity

Aksi takdirde kullanmalısınız

numeric_limits<double>::lowest()

C ++ 11'de tanıtılan.

lowest()Müsait değilse , geri dönebilirsiniz

-numeric_limits<double>::max()

lowest()prensip olarak farklılık gösterebilir , ancak normalde uygulamada değildir.


Sonlu ve sonsuz değer arasındaki fark için +1! Ancak standart, simetrik kayan nokta kodlamasını garanti etmez. Yani -numeric_limits<double>::max()pratikte çalışsa bile teoride tam olarak taşınabilir değildir.
Christophe

@Christophe: [x] düzeltildi
Christoph

10

Gerçekten taşınabilir bir C ++ çözümü

C ++ 11'den itibaren kullanabilirsiniz numeric_limits<double>::lowest(). Standarda göre, tam olarak aradığınız şeyi döndürür:

Başka sonlu değer y'nin olmadığı sonlu bir x değeri y < x.
Olduğu tüm uzmanlıklar için anlamlıdır is_bounded != false.

Çevrimiçi demo


Burada taşınabilir olmayan birçok C ++ yanıtı!

Pek çok cevap var -std::numeric_limits<double>::max().

Neyse ki, çoğu durumda iyi çalışacaklar. Kayan nokta kodlama şemaları, bir mantisteki bir sayıyı ve bir üssü ayrıştırır ve bunların çoğu (örneğin, popüler IEEE-754 ) mantise ait olmayan ayrı bir işaret biti kullanır. Bu, yalnızca işareti çevirerek en büyük pozitifin en küçük negatife dönüştürülmesine izin verir:

görüntü açıklamasını buraya girin

Bunlar neden taşınabilir değil?

Standart herhangi bir kayan nokta standardı empoze etmez.

Argümanımın biraz teorik olduğuna katılıyorum, ancak bazı eksantrik derleyici yapıcılarının, ikinin tamamlayıcısının bazı varyasyonlarında kodlanmış bir mantis ile devrim niteliğinde bir kodlama şeması kullanacağını varsayalım . İkinin tümleyen kodlaması simetrik değildir. örneğin işaretli 8 bitlik bir karakter için maksimum pozitif 127'dir, ancak minimum negatif -128'dir. Bu nedenle, bazı kayan nokta kodlamalarının benzer asimetrik davranışlar gösterdiğini hayal edebiliriz.

Bunun gibi herhangi bir kodlama şemasının farkında değilim, ancak asıl mesele şu ki , standart işaret çevirmenin istenen sonucu vereceğini garanti etmiyor . Bu yüzden bu popüler cevap (üzgünüm çocuklar!) Tamamen taşınabilir standart çözüm olarak kabul edilemez! / * en azından bunun numeric_limits<double>::is_iec559doğru olduğunu iddia etmediyseniz değil * /



1

Asıl soru sonsuzlukla ilgilidir. Öyleyse neden kullanmıyorsun

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

IEEE tanımına göre? Elbette bunu reddedebilirsiniz.


İyi fikir ! Ve işe yarıyor . Ama sadecenumeric_limits<double>::has_infinity && ! numeric_limits<double>::traps
Christophe

1

Bir C (++) programında en küçük negatif değeri temsil etmenin (örneğin negatif sonsuzluğu kullanmak için) standart ve / veya taşınabilir bir yolu var mı?

C yaklaşımı.

Çoğu uygulama +/- sonsuzlukları destekler, bu nedenle en negatif doubledeğerdir -INFINITY.

#include <math.h>
double most_negative = -INFINITY;

Standart ve / veya taşınabilir bir yol var mı ....?

Şimdi başka durumları da düşünmemiz gerekiyor:

  • Sonsuzluk yok

Basitçe -DBL_MAX.

  • Sadece imzasız bir sonsuzluk.

Bu durumda beklerdim, OP tercih ederdi -DBL_MAX.

  • Büyüklüğünden daha büyük olan normal olmayan değerler DBL_MAX.

Bu alışılmadık bir durumdur, muhtemelen OP'nin endişesi dışında. Ne zaman doublebir bir çift olarak kodlanır kayan nokta istenen aralığın / eksen sapmasını elde etmek için, (bakınız çift çift maksimum orada var) , normal double ve belki de daha büyük bir de normal bir. Her ikisinin DBL_MAXde en büyüğü, en büyük normale atıfta bulunulması gerekip gerekmediği konusunda tartışmalar gördüm .

Neyse ki bu ikili yaklaşım genellikle -sonsuzluğu içerir, bu nedenle en negatif değer kalır -INFINITY.


Daha fazla taşınabilirlik için kod rotadan aşağı inebilir

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

-1

Float istisnalarını etkinleştirmediyseniz (ki bunu imho yapmamalısınız), basitçe şunu söyleyebilirsiniz:

double neg_inf = -1/0.0;

Bu, negatif sonsuzluk verir. Bir şamandıraya ihtiyacınız varsa, sonucu ya

float neg_inf = (float)-1/0.0;

veya tek duyarlıklı aritmetik kullanın

float neg_inf = -1.0f/0.0f;

Sonuç her zaman aynıdır, hem tek hem de çift kesinlikte negatif sonsuzluğun tam olarak bir temsili vardır ve beklediğiniz gibi birbirlerine dönüşürler.


Bunu sadece yazmak yerine neden -INFINITY
MM

Ayrıca sonsuzluk var olabilir veya olmayabilir ve eğer varsa, o zaman pozitif ve negatif ayırt edilemez (Standart C'de).
MM

Birçok derleyicide ve / veya mimaride C / C ++ kodunuz, çoğunuzun sonsuzluk ve NaN değerlerini yaymasını yavaşlatır.
markgalassi

@markgalassi Lütfen daha yakından bakın: Bunun sabit bir değerleneg_inf başlatıldığını fark edeceksiniz . Derleyici değeri hesaplamakla ilgilenecektir . Ve bunu bir maks. Hesaplamak için boş değer olarak kullandığınızda, ilk yineleme genellikle onun üzerine daha büyük bir değer yazacaktır. Yani performans pek sorun değil. Ve OP özellikle "örneğin negatif sonsuzluğu kullanmak" hakkında sorar ve gerçekten de buna tek doğru cevaptır. Doğru ve faydalı bir cevaba olumsuz oy verdiniz. inf-inf
cmaster
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.