Float ve double arasındaki fark nedir?


420

Çift kesinlik ve tek kesinlik arasındaki farkı okudum. Bununla birlikte, çoğu durumda floatve doublebirbirinin yerine kullanılabilir gibi görünmektedir, yani birini veya diğerini kullanmak sonuçları etkilemez gibi görünmektedir. Gerçekten böyle mi? Şamandıralar ve çiftler ne zaman değiştirilebilir? Aralarındaki farklar nelerdir?

Yanıtlar:


521

Büyük farklılık.

Adından da anlaşılacağı gibi, a [1] 'double in 2 katına sahiptir . Genel olarak a , 15 ondalık basamak hassasiyete sahiptir.floatdoublefloat , 7'dir.

Basamak sayısı şu şekilde hesaplanır:

double52 mantis biti + 1 gizli biti var: log (2 53 ) ÷ log (10) = 15,95 basamak

float23 mantis biti + 1 gizli biti vardır: log (2 24 ) ÷ log (10) = 7.22 basamak

Bu hassas kayıp, tekrarlanan hesaplamalar yapıldığında daha büyük kesme hatalarına yol açabilir, örn.

float a = 1.f / 81;
float b = 0;
for (int i = 0; i < 729; ++ i)
    b += a;
printf("%.7g\n", b); // prints 9.000023

süre

double a = 1.0 / 81;
double b = 0;
for (int i = 0; i < 729; ++ i)
    b += a;
printf("%.15g\n", b); // prints 8.99999999999996

Ayrıca, şamandıra maksimum değeri yaklaşık 3e38, ancak çift yaklaşık 1.7e308, bu yüzden kullanmak float"sonsuzluk" (yani özel bir kayan nokta sayısı) doublebasit bir şeyden çok daha kolay vurabilir , örneğin 60 faktöriyelini hesaplamak.

Test sırasında, birkaç test vakası bu büyük sayıları içerebilir, bu da şamandıralar kullanırsanız programlarınızın başarısız olmasına neden olabilir.


Tabii ki, bazen doubleyeterince doğru bile değil, bu yüzden bazen long double[1] (yukarıdaki örnek Mac'te 9.000000000000000066 verir), ancak tüm kayan nokta türleri yuvarlama hatalarından muzdariptir , bu nedenle hassasiyet çok önemliyse (örn. Para işleme) intveya bir kesir sınıfını kullanmalısınız .


Ayrıca, +=hatalar hızla biriktiğinden çok sayıda kayan nokta sayısını toplamak için kullanmayın . Python kullanıyorsanız, kullanın fsum. Aksi takdirde, Kahan toplama algoritmasını uygulamaya çalışın .


[1]: C ve C ++ standartları float, doubleve öğelerinin temsilini belirtmez long double. Her üçünün de IEEE çift kesinlikli olarak uygulanması mümkündür. Bununla birlikte, en mimarilerinde (gcc MSVC; 86, 64, KOL) float olan gerçekten nokta sayısı (binary32) değişken bir IEEE tek hassasiyetli ve double bir IEEE çift kesinlikli kayar ayırmalı sayı (binary64).


9
Toplama için genel tavsiye, toplanmadan önce kayan nokta sayılarınızı büyüklüğe (ilk önce en küçük) göre sıralamaktır.
R .. GitHub BUZA YARDIMCI DURDUR

C / C ++ şamandıra ve çift neredeyse her zaman IEEE tek ve çift kesinlik sırasıyla C / C ++ uzun çift CPU, derleyici ve işletim sistemi bağlı olarak çok daha değişken olduğunu unutmayın. Bazen çift ile aynı, bazen sisteme özgü genişletilmiş format, Bazen IEEE dörtlü hassasiyet.
plugwash

@ R.. GitHubSTOPHELPINGICE: neden? Açıklayabilir misiniz?
InQusitive

@InQusitive: Örneğin, 2 ^ 24 değerinden sonra 1 değerinin 2 ^ 24 tekrarından oluşan bir dizi düşünün. Sırayla toplama işlemi 2 ^ 24 üretir. Tersine çevirme 2 ^ 25 üretir. Tabii ki, herhangi bir siparişin tek bir akümülatörle felaketle yanlış olduğu ancak ilk önce en küçük-büyüklük-en iyisi olduğu örnekler verebilir (örneğin 1'den 2 ^ 25 tekrar yapın). Daha iyisini yapmak için bir çeşit ağaca ihtiyacınız var.
R .. GitHub DURDURMAK BUZ

56

Standart C99 (ISO-IEC 9899 6.2.5 §10) veya C ++ 2003 (ISO-IEC 14882-2003 3.1.9 §8) standartları şöyle der:

Orada üç kayan nokta türleri şunlardır: float, doubleve long double. Tip double, en az olduğu kadar hassaslık sağlar floatve tip long double, en az olduğu kadar hassastır double. Çeşidi değerler kümesi floattipi değerler kümesinin bir alt kümesidir double; türün değer kümesi, türün değer doublekümesinin bir alt kümesidir long double.

C ++ standardı şunları ekler:

Kayan nokta türlerinin değer gösterimi uygulama tanımlıdır.

Her Bilgisayar Bilimcisinin IEEE kayan nokta standardını derinlemesine kapsayan Kayan Nokta Aritmetiği Hakkında Bilmesi Gerekenler'e göz atmanızı öneririm . Temsil ayrıntılarını öğreneceksiniz ve büyüklük ve kesinlik arasında bir denge olduğunu anlayacaksınız. Büyüklük azaldıkça kayan nokta gösteriminin kesinliği artar, dolayısıyla -1 ile 1 arasındaki kayan nokta sayıları en hassas olanlardır.


27

İkinci dereceden bir denklem verildiğinde: x 2  - 4.0000000  x  + 3.9999999 = 0, 10 anlamlı basamağa giden kesin kökler, r 1  = 2.000316228 ve r 2  = 1.999683772'dir.

Kullanılması floatve doublebiz bir test programı yazabilirsiniz:

#include <stdio.h>
#include <math.h>

void dbl_solve(double a, double b, double c)
{
    double d = b*b - 4.0*a*c;
    double sd = sqrt(d);
    double r1 = (-b + sd) / (2.0*a);
    double r2 = (-b - sd) / (2.0*a);
    printf("%.5f\t%.5f\n", r1, r2);
}

void flt_solve(float a, float b, float c)
{
    float d = b*b - 4.0f*a*c;
    float sd = sqrtf(d);
    float r1 = (-b + sd) / (2.0f*a);
    float r2 = (-b - sd) / (2.0f*a);
    printf("%.5f\t%.5f\n", r1, r2);
}   

int main(void)
{
    float fa = 1.0f;
    float fb = -4.0000000f;
    float fc = 3.9999999f;
    double da = 1.0;
    double db = -4.0000000;
    double dc = 3.9999999;
    flt_solve(fa, fb, fc);
    dbl_solve(da, db, dc);
    return 0;
}  

Programı çalıştırmak bana şunları verir:

2.00000 2.00000
2.00032 1.99968

Sayıların büyük olmadığını, ancak kullanarak iptal efektleri aldığınızı unutmayın float.

(Aslında, yukarıdaki tek veya çift kesinlikli kayar nokta sayıları kullanarak ikinci dereceden denklemleri çözmenin en iyi yolu değildir, ancak daha kararlı bir yöntem kullansa bile cevap değişmeden kalır .)


19
  • Bir çift 64 ve tek kesinlik (float) 32 bittir.
  • Çifte daha büyük bir mantis (gerçek sayının tamsayı bitleri) vardır.
  • Herhangi bir yanlışlık çifte daha küçük olacaktır.

12

Kayan nokta hesaplamalarında yer alan sayıların boyutu en alakalı şey değildir. İlgili olarak yapılan hesaplamadır.

Temel olarak, bir hesaplama gerçekleştiriyorsanız ve sonuç irrasyonel bir sayı veya yinelenen ondalıksa, bu sayı kullandığınız sonlu boyut veri yapısına sıkıştırıldığında yuvarlama hataları olacaktır. Çifte şamandıra boyutunun iki katı olduğundan yuvarlama hatası çok daha küçük olacaktır.

Testler özellikle bu tür hatalara neden olacak sayılar kullanabilir ve bu nedenle kodunuzda uygun türü kullandığınızı test edebilir.


9

32 bit uzunluğundaki tip şamandıra, 7 basamak hassasiyete sahiptir. Çok büyük veya çok küçük aralığa (+/- 3.4 * 10 ^ 38 veya * 10 ^ -38) sahip değerler depolayabilse de, yalnızca 7 önemli basamağı vardır.

64 bit uzunluğunda, çift tip daha büyük bir aralığa (* 10 ^ + / - 308) ve 15 basamak hassasiyete sahiptir.

Belirli bir derleyici / OS eşleştirmesi hizalama amacıyla 12-16 bayt olarak saklayabilse de, long double türü nominal olarak 80 bittir. Uzun çifte gülünç derecede büyük ve 19 basamak hassasiyete sahip bir üs var. Microsoft, sonsuz bilgelikleriyle, iki katını 8 bayta kadar sınırlandırır;

Genel olarak, kayan nokta değeri / değişkenine ihtiyaç duyduğunuzda yalnızca double türünü kullanın. İfadelerde kullanılan değişmez kayan nokta değerleri varsayılan olarak iki kat olarak değerlendirilir ve kayan nokta değerlerini döndüren matematik işlevlerinin çoğu iki katına döner. Sadece çift kullanırsanız, birçok baş ağrısını ve dakikayı kurtaracaksınız.



9

Sadece beni anlamaya sonsuza dek süren bir hatayla karşılaştım ve potansiyel olarak size şamandıra hassasiyetine iyi bir örnek verebilirim.

#include <iostream>
#include <iomanip>

int main(){
  for(float t=0;t<1;t+=0.01){
     std::cout << std::fixed << std::setprecision(6) << t << std::endl;
  }
}

Çıktı

0.000000
0.010000
0.020000
0.030000
0.040000
0.050000
0.060000
0.070000
0.080000
0.090000
0.100000
0.110000
0.120000
0.130000
0.140000
0.150000
0.160000
0.170000
0.180000
0.190000
0.200000
0.210000
0.220000
0.230000
0.240000
0.250000
0.260000
0.270000
0.280000
0.290000
0.300000
0.310000
0.320000
0.330000
0.340000
0.350000
0.360000
0.370000
0.380000
0.390000
0.400000
0.410000
0.420000
0.430000
0.440000
0.450000
0.460000
0.470000
0.480000
0.490000
0.500000
0.510000
0.520000
0.530000
0.540000
0.550000
0.560000
0.570000
0.580000
0.590000
0.600000
0.610000
0.620000
0.630000
0.640000
0.650000
0.660000
0.670000
0.680000
0.690000
0.700000
0.710000
0.720000
0.730000
0.740000
0.750000
0.760000
0.770000
0.780000
0.790000
0.800000
0.810000
0.820000
0.830000
0.839999
0.849999
0.859999
0.869999
0.879999
0.889999
0.899999
0.909999
0.919999
0.929999
0.939999
0.949999
0.959999
0.969999
0.979999
0.989999
0.999999

0.83'ten sonra görebileceğiniz gibi, hassasiyet önemli ölçüde azalır.

Ancak, tçift ​​olarak ayarlarsam böyle bir sorun olmaz.

Programımı bozan bu küçük hatayı fark etmek beş saatimi aldı.


4
sadece emin olmak için: Sorununuzun çözümü tercihen bir int kullanmak mı? 100 kez yinelemek istiyorsanız, bir double kullanmak yerine int ile
saymalısınız

8
Kullanmak doubleburada iyi bir çözüm değildir. intKayar nokta değerinizi almak için dahili bir çarpma işlemi yapmak ve saymak için kullanılır .
Richard


3

Kayan nokta sayılarını kullanırken, yerel testlerinizin sunucu tarafında yapılan testlerle tamamen aynı olacağına güvenemezsiniz. Ortam ve derleyici muhtemelen yerel sisteminizde ve son testlerin yapıldığı yerde farklıdır. Özellikle iki kayan nokta sayısını karşılaştırmaya çalışırsanız, bu sorunu bazı TopCoder yarışmalarında daha önce birçok kez gördüm.


3

Yerleşik karşılaştırma işlemleri, 2 sayıyı kayan nokta ile karşılaştırdığınızda olduğu gibi farklılık gösterir, veri türündeki (yani float veya double) fark farklı sonuçlara neden olabilir.


1

Biri gömülü işleme ile çalışırsa, sonuçta temel donanım (örn. FPGA veya belirli bir işlemci / mikrodenetleyici modeli) donanımda en iyi şekilde uygulanırken, çift yazılım rutinlerini kullanır. Dolayısıyla, bir şamandıranın hassasiyeti ihtiyaçları karşılamak için yeterliyse, program şamandıra ve daha sonra iki kat daha hızlı çalışacaktır. Diğer cevaplarda belirtildiği gibi, birikim hatalarına dikkat edin.


-1

Bir int(tam sayı) 'dan farklı olarak float, a ondalık bir noktaya sahiptir ve a double. Ancak ikisi arasındaki fark double, a'nın a'nın iki katı kadar ayrıntılı olmasıdır float, yani ondalık noktadan sonraki sayıların iki katı olabilir.


4
Hiç de öyle değil. Aslında birçok iki kat demektir ayrılmaz ondalık basamak ve çift daha fazladır. Kesirli basamaklar ve kesinlik arasındaki ilişki doğrusal değildir: değere bağlıdır: örneğin 0,5 kesindir ancak 0,33333333333333333333 değildir.
Lorne Marquis
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.