Son sorumun cevabını aldım (neden böyle düşünmediğimi bilmiyorum). Bir basıyordum double
kullanarak cout
bunu beklemiyordum zaman anladınız yuvarlanır. Nasıl cout
baskı yapabilirimdouble
Tam hassasiyet kullanarak ?
Son sorumun cevabını aldım (neden böyle düşünmediğimi bilmiyorum). Bir basıyordum double
kullanarak cout
bunu beklemiyordum zaman anladınız yuvarlanır. Nasıl cout
baskı yapabilirimdouble
Tam hassasiyet kullanarak ?
Yanıtlar:
Hassasiyeti doğrudan ayarlayabilir std::cout
ve std::fixed
format belirleyiciyi kullanabilirsiniz .
double d = 3.14159265358979;
cout.precision(17);
cout << "Pi: " << fixed << d << endl;
#include <limits>
Bir şamandıra veya çiftin maksimum hassasiyetini elde edebilirsiniz .
#include <limits>
typedef std::numeric_limits< double > dbl;
double d = 3.14159265358979;
cout.precision(dbl::max_digits10);
cout << "Pi: " << d << endl;
cout.precision(numeric_limits<double>::digits10 + 2);
sadece 16'yı alıyorum ....
max_digits10
aynısını göstermek için tanıtıldı . Yanıtın bunu yansıtması düzeltildi.
Kullanım std::setprecision
:
std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
std::setprecision (17)
çift için, @Bill Lizard'ın cevap yorumlara bakınız.
İşte ne kullanacağım:
std::cout << std::setprecision (std::numeric_limits<double>::digits10 + 1)
<< 3.14159265358979
<< std::endl;
Temel olarak sınırlar paketi, tüm yapı türleri için özelliklere sahiptir.
Kayan nokta sayılarının özelliklerinden biri (float / double / long double) digits10 özelliğidir. Bu, taban 10'daki bir kayan nokta sayısının doğruluğunu (kesin terminolojiyi unutuyorum) tanımlar.
Bkz. Http://www.cplusplus.com/reference/std/limits/numeric_limits.html
Diğer özellikler hakkında ayrıntılar için.
std::setprecision()
: #include <iomanip>
std::numeric_limits<double>
yerine olmalınumberic_limits<double>
1
için std::numeric_limits<double>::digits10
?
max_digits10
, keyfi değil digits10+2
. Aksi takdirde, söz konusu float
, long double
, boost::multiprecision::float128
, gerekir orada beri bu, başarısız olacaktır +3
yerine +2
.
İostreams yolu biraz tıknaz. Kullanmayı tercih ederim boost::lexical_cast
çünkü benim için doğru hassasiyeti hesaplıyor. Ve hızlı da.
#include <string>
#include <boost/lexical_cast.hpp>
using boost::lexical_cast;
using std::string;
double d = 3.14159265358979;
cout << "Pi: " << lexical_cast<string>(d) << endl;
Çıktı:
Pi: 3.14159265358979
Tam hassasiyetle, amaçlanan değere en iyi yaklaşımı gösterecek kadar hassas olduğunu varsayıyorum, ancak double
baz 2 temsili kullanılarak saklanan ve baz 2'nin 1.1
tam olarak önemsiz bir şeyi temsil edemeyeceği belirtilmelidir . Gerçek çiftin tam hassasiyetini elde etmenin tek yolu (YUVARLAK KAPALI HATALI), ikili bitleri (veya altıgen nybbles) yazdırmaktır. Bunu yapmanın bir yolu, yazıyor double
bir etmek union
ve daha sonra bit tamsayı değeri yazdırmak.
union {
double d;
uint64_t u64;
} x;
x.d = 1.1;
std::cout << std::hex << x.u64;
Bu size çiftin% 100 doğru hassasiyetini verecektir ... ve tamamen okunamaz olacaktır çünkü insanlar IEEE çift formatını okuyamaz! Wikipedia , ikili bitlerin nasıl yorumlanacağı konusunda iyi bir yazıya sahiptir.
Daha yeni C ++ 'da şunları yapabilirsiniz:
std::cout << std::hexfloat << 1.1;
Bir çiftin tam hassasiyetle nasıl gösterileceği aşağıda açıklanmıştır:
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;
Bu görüntülenir:
100,0000000000005
max_digits10, tüm farklı çift değerleri benzersiz bir şekilde temsil etmek için gereken basamak sayısıdır. max_digits10, ondalık basamaktan önceki ve sonraki basamak sayısını temsil eder.
Std :: fixed ile set_precision (max_digits10) kullanmayın.
Sabit gösterimde, set_precision () yalnızca ondalık noktadan sonraki basamak sayısını ayarlar . Max_digits10 , ondalık noktadan önceki ve sonraki basamak sayısını temsil ettiğinden bu yanlıştır .
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::fixed << std::setprecision(precision) << d << std::endl;
Bu yanlış sonuç gösteriyor:
100,00000000000049738
Not: Başlık dosyaları gerekir
#include <iomanip>
#include <limits>
100.0000000000005
, tam olarak bir olarak gösterilmediği için olur double
. (Olması gerektiği gibi görünebilir, ancak normalleşmez , yani ikili temsili). Bunu görmek için, deneyin: 100.0000000000005 - 100
. Anlıyoruz 4.973799150320701e-13
.
Bir
double
değeri cout kullanarak tam hassasiyetle nasıl yazdırabilirim ?
Hassasiyeti kullanın hexfloat
veya
kullanın scientific
ve ayarlayın
std::cout.precision(std::numeric_limits<double>::max_digits10 - 1);
std::cout << std::scientific << 1.0/7.0 << '\n';
// C++11 Typical output
1.4285714285714285e-01
Çok fazla cevap 1) temel 2) sabit / bilimsel düzen veya 3) hassasiyetten sadece birini ele almaktadır. Hassaslıkla çok fazla cevap gerekli olan uygun değeri sağlamaz. Bu yüzden eski bir sorunun cevabı.
A double
kesinlikle taban 2 kullanılarak kodlanır. C ++ 11 ile doğrudan bir yaklaşım kullanarak yazdırmaktır std::hexfloat
.
Ondalık olmayan bir çıktı kabul edilebilirse, işimiz bitmiştir.
std::cout << "hexfloat: " << std::hexfloat << exp (-100) << '\n';
std::cout << "hexfloat: " << std::hexfloat << exp (+100) << '\n';
// output
hexfloat: 0x1.a8c1f14e2af5dp-145
hexfloat: 0x1.3494a9b171bf5p+144
fixed
veya scientific
?A double
, kayan nokta tipidir, sabit nokta değildir .
Do not kullanmak std::fixed
bu küçük yazdırmak için başarısız olarak double
bir şey ama 0.000...000
. Büyük için double
, birçok basamak, belki de yüzlerce şüpheli bilgilendirme basar .
std::cout << "std::fixed: " << std::fixed << exp (-100) << '\n';
std::cout << "std::fixed: " << std::fixed << exp (+100) << '\n';
// output
std::fixed: 0.000000
std::fixed: 26881171418161356094253400435962903554686976.000000
Tam hassasiyetle yazdırmak için ilk önce std::scientific
"bilimsel gösterimde kayan nokta değerleri yazacak" kullanın. Ondalık noktadan sonraki 6 basamaklı varsayılan değerin, yetersiz bir miktarın bir sonraki noktada ele alındığına dikkat edin.
std::cout << "std::scientific: " << std::scientific << exp (-100) << '\n';
std::cout << "std::scientific: " << std::scientific << exp (+100) << '\n';
// output
std::scientific: 3.720076e-44
std::scientific: 2.688117e+43
Bir double
ikili tabanı 2 kodlamakta Bu genellikle 53 bit 2. çeşitli güçler arasında aynı hassas kullanılarak kodlanır.
[1.0 ... 2.0) 2 53 farklı double
,
[2.0 ... 4.0) 2 53 farklı double
,
[4.0 ... 8.0) 2 53 farklı double
,
[8.0 ... 10.0) 2 / 8 * 2 53 farklı double
.
Yine de, kod N
önemli basamaklarla ondalık olarak yazdırılıyorsa , kombinasyon sayısı [1.0 ... 10.0) 9/10 * 10 N'dir .
N
Seçilen (kesinlik) ne olursa olsun , double
ondalık metin arasında bire bir eşleme olmaz . Bir sabit N
seçilirse, bazen belirli double
değerler için gerçekten gerekenden biraz daha fazla veya daha az olacaktır . Çok az ( a)
aşağıda) veya çok fazla ( aşağıda) hata verebiliriz b)
.
3 aday N
:
a) Metin-metinden N
dönüştürürken double
herkes için aynı metne ulaştığımız şekilde bunu kullanın double
.
std::cout << dbl::digits10 << '\n';
// Typical output
15
b) bir kullanma N
dönüştürürken çok double
-text- double
aynı varmak double
için tüm double
.
// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17
Ne zaman max_digits10
mevcut değildir nedeniyle tabanın 2 ve baz 10 özelliklerine, o notu digits10 + 2 <= max_digits10 <= digits10 + 3
, kullanabileceğimiz digits10 + 3
yeterli ondalık basamak sigorta yazdırılır.
c) Değere N
göre değişen bir kullanın .
Bu, kod en az metni ( N == 1
) veya tam bir değeri double
( N == 1000-ish
durumunda denorm_min
). Ancak bu “iş” olduğu ve muhtemelen OP'nin hedefi olmadığı için bir kenara bırakılacaktır.
Genellikle b) " double
değeri tam hassasiyetle basmak" için kullanılır . Bazı uygulamalar a) çok fazla bilgi vermemede hata yapmayı tercih edebilir.
İle .scientific
, .precision()
ondalık noktadan sonra yazdırılacak basamak sayısını ayarlar, böylece 1 + .precision()
basamaklar yazdırılır. Kodun max_digits10
toplam basamağa ihtiyacı var,.precision()
, ile çağrılır max_digits10 - 1
.
typedef std::numeric_limits< double > dbl;
std::cout.precision(dbl::max_digits10 - 1);
std::cout << std::scientific << exp (-100) << '\n';
std::cout << std::scientific << exp (+100) << '\n';
// Typical output
3.7200759760208361e-44
2.6881171418161356e+43
//1234567890123456 17 total digits
precision()
Bilimsel mod için ondalık basamak sayısını belirleyen haklısınız . Belirtmeden scientific
, üs hariç toplam basamak sayısını ayarlar. Sayı değerinize bağlı olarak yine de bilimsel çıktı alabilirsiniz, ancak daha sonra belirttiğinizden daha az hane alabilirsiniz. Örnek: için cout.precision(3); cout << 1.7976931348623158e+308; // "1.8e+308"
sonuçlar printf
farklı olabilir. Kafa karıştırıcı şeyler farkında olmalıdır.
char buf[DBL_DECIMAL_DIG + 3 + 5]; sprintf(buf, "%.*g", DBL_DECIMAL_DIG, d);
Ekstra karakterler şöyledir: işaret, ondalık nokta, arka sıfır, e [+ | -], üs için 3 basamak ( DBL_MAX_10_EXP = 308). Bu nedenle gerekli toplam karakter sayısı 25'tir.
printf("%.12f", M_PI);
% .12f, 12 basamak hassasiyetle kayan nokta anlamına gelir.
En portatif olarak ...
#include <limits>
using std::numeric_limits;
...
cout.precision(numeric_limits<double>::digits10 + 1);
cout << d;
Ostream ile :: duyarlık (int)
cout.precision( numeric_limits<double>::digits10 + 1);
cout << M_PI << ", " << M_E << endl;
getirecek
3.141592653589793, 2.718281828459045
Neden "+1" demek zorundasınız? Hiçbir fikrim yok, ama bundan elde ettiğiniz ekstra rakam doğrudur.
Bu noktadan sonra iki ondalık basamağa kadar olan değeri gösterecektir.
#include <iostream>
#include <iomanip>
double d = 2.0;
int n = 2;
cout << fixed << setprecison(n) << d;
Buraya bakın: Sabit noktalı gösterim
Sabit kayan nokta gösterimini kullan Str akışı için kayan nokta biçimi bayrağını sabit olarak ayarlar.
Kayan alan sabit olarak ayarlandığında, kayan nokta değerleri sabit nokta gösterimi kullanılarak yazılır: değer, tam olarak ondalık kısımda, kesinlik alanı (kesinlik) tarafından belirtilen sayıda basamak ile temsil edilir ve üs parçası yoktur.
Ondalık duyarlığı ayarlama Çıktı işlemlerinde kayan nokta değerlerini biçimlendirmek için kullanılacak ondalık duyarlığı ayarlar.
Kayan noktaları temsil etmek için IEEE standardını biliyorsanız, standartın kapsamı dışında tam hassasiyetle kayan noktaları göstermenin imkansız olduğunu bilirsiniz , yani her zaman gerçek değerin yuvarlanması.
İlk önce değerin kapsam dahilinde olup olmadığını kontrol etmeniz gerekir , eğer evetse, şunu kullanın:
cout << defaultfloat << d ;
Varsayılan kayan nokta gösterimini kullan str akışı için kayan nokta biçimi bayrağını defaultfloat olarak ayarlar.
Kayan alan varsayılan yüzeye ayarlandığında, kayan nokta değerleri varsayılan gösterim kullanılarak yazılır: gösterim, akışın ondalık duyarlığına (kesinlik) kadar gerektiği kadar çok sayıda anlamlı basamak kullanır ve ondalık noktadan önceki ve sonraki sayıları sayar (varsa) ).
Bu aynı zamanda varsayılan davranışıdır cout
, yani açıkça kullanmazsınız.
fixed
? İledouble h = 6.62606957e-34;
,fixed
bana verir0.000000000000000
vescientific
çıktılar6.626069570000000e-34
.