Apa perbedaan antara float dan double?

420

Saya telah membaca tentang perbedaan antara presisi ganda dan presisi tunggal. Namun, dalam banyak kasus, floatdan doubletampaknya dapat dipertukarkan, yaitu menggunakan satu atau yang lain tampaknya tidak mempengaruhi hasil. Benarkah ini masalahnya? Kapan mengapung dan ganda dipertukarkan? Apa perbedaan di antara mereka?

VaioIsBorn
sumber

Jawaban:

521

Perbedaan besar

Sesuai namanya, a doublememiliki 2x presisi [1] . Secara umum a memiliki 15 digit desimal presisi, sementarafloatdoublefloat memiliki 7.

Begini cara menghitung jumlah digit:

doublememiliki 52 mantissa bit + 1 bit tersembunyi: log (2 53 ) ÷ log (10) = 15,95 digit

floatmemiliki 23 bit mantissa + 1 bit tersembunyi: log (2 24 ) ÷ log (10) = 7.22 digit

Kehilangan presisi ini dapat menyebabkan kesalahan pemotongan yang lebih besar terakumulasi ketika perhitungan berulang dilakukan, misalnya

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

sementara

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

Juga, nilai maksimum float adalah tentang 3e38, tetapi dua kali lipat adalah tentang 1.7e308, jadi menggunakan floatdapat menekan "tak terbatas" (yaitu angka floating-point khusus) lebih mudah daripadadouble untuk sesuatu yang sederhana, misalnya menghitung faktorial 60.

Selama pengujian, mungkin beberapa kasus uji berisi angka besar ini, yang dapat menyebabkan program Anda gagal jika Anda menggunakan pelampung.


Tentu saja, kadang-kadang, bahkan doubletidak cukup akurat, maka kita kadang-kadang memiliki long double[1] (contoh di atas memberikan 9,00000000000000000066 pada Mac), tetapi semua tipe floating point menderita kesalahan pembulatan , jadi jika presisi sangat penting (misalnya uang) pemrosesan) Anda harus menggunakan intatau kelas pecahan.


Selain itu, jangan gunakan +=untuk menjumlahkan banyak angka floating point, karena kesalahan menumpuk dengan cepat. Jika Anda menggunakan Python, gunakan fsum. Jika tidak, cobalah untuk mengimplementasikan algoritma penjumlahan Kahan .


[1]: Standar C dan C ++ tidak menentukan representasi float, doubledan long double. Ada kemungkinan bahwa ketiganya diimplementasikan sebagai presisi ganda IEEE. Namun demikian, untuk sebagian besar arsitektur (gcc, MSVC; x86, x64, ARM) float adalah memang IEEE presisi tunggal floating point nomor (binary32), dan double merupakan sebuah IEEE double-presisi floating point nomor (binary64).

kennytm
sumber
9
Saran yang biasa untuk penjumlahan adalah untuk mengurutkan angka floating point Anda dengan besarnya (terkecil terlebih dahulu) sebelum dijumlahkan.
R .. GitHub BERHENTI MEMBANTU ICE
Perhatikan bahwa sementara C / C ++ float dan double hampir selalu IEEE tunggal dan ganda, masing-masing C / C ++ long double jauh lebih bervariasi tergantung pada CPU, kompiler dan OS Anda. Kadang-kadang sama dengan ganda, kadang-kadang beberapa format diperpanjang khusus sistem, Kadang-kadang presisi IEEE quad.
plugwash
@ R..GitHubSTOPHELPINGICE: mengapa? Bisakah Anda jelaskan?
InQusitive
@InQusitive: Pertimbangkan misalnya array yang terdiri dari nilai 2 ^ 24 diikuti oleh 2 ^ 24 pengulangan dari nilai 1. Penjumlahan secara berurutan menghasilkan 2 ^ 24. Membalik menghasilkan 2 ^ 25. Tentu saja Anda dapat membuat contoh (misalnya membuatnya 2 ^ 25 pengulangan 1) di mana setiap pesanan akhirnya menjadi salah besar dengan akumulator tunggal tetapi terkecil terkecil-pertama adalah yang terbaik di antara itu. Untuk melakukan yang lebih baik Anda perlu semacam pohon.
R .. GitHub BERHENTI MEMBANTU ICE
56

Berikut adalah apa yang dikatakan standar C99 (ISO-IEC 9899 6.2.5 §10) atau C ++ 2003 (ISO-IEC 14882-2003 3.1.9 §8):

Ada tiga tipe floating point: float, double, dan long double. Jenis ini doublemenyediakan setidaknya sebanyak presisi float, dan jenis long doublemenyediakan setidaknya sebanyak presisi double. Himpunan nilai jenis floatadalah himpunan bagian dari nilai-nilai jenis double; himpunan nilai jenis doubleadalah himpunan bagian dari nilai-nilai jenis long double.

Standar C ++ menambahkan:

Representasi nilai tipe floating-point didefinisikan sebagai implementasi.

Saya akan menyarankan untuk melihat pada apa yang Harus Tahu Setiap Ilmuwan Komputer Tentang Aritmatika Floating-Point yang mencakup standar IEEE floating-point secara mendalam. Anda akan belajar tentang detail representasi dan Anda akan menyadari ada tradeoff antara besarnya dan presisi. Ketepatan representasi titik apung meningkat dengan besarnya berkurang, karenanya angka titik apung antara -1 dan 1 adalah yang paling presisi.

Gregory Pakosz
sumber
27

Diberikan persamaan kuadrat: x 2  - 4.0000000  x  + 3.9999999 = 0, akar yang tepat untuk 10 digit signifikan adalah, r 1  = 2.000316228 dan r 2  = 1.999683772.

Dengan menggunakan floatdan double, kita dapat menulis program pengujian:

#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;
}  

Menjalankan program memberi saya:

2.00000 2.00000
2.00032 1.99968

Perhatikan bahwa jumlahnya tidak besar, tetapi Anda tetap mendapatkan efek pembatalan menggunakan float.

(Pada kenyataannya, di atas bukan cara terbaik untuk memecahkan persamaan kuadratik menggunakan angka floating-point presisi tunggal atau ganda, tetapi jawabannya tetap tidak berubah bahkan jika seseorang menggunakan metode yang lebih stabil .)

Alok Singhal
sumber
19
  • Double adalah 64 dan single precision (float) adalah 32 bit.
  • Ganda memiliki mantissa yang lebih besar (bit integer dari bilangan real).
  • Setiap ketidakakuratan akan lebih kecil di ganda.
graham.reeds
sumber
12

Ukuran angka yang terlibat dalam perhitungan float-point bukanlah hal yang paling relevan. Ini perhitungan yang sedang dilakukan yang relevan.

Intinya, jika Anda melakukan perhitungan dan hasilnya adalah bilangan irasional atau desimal berulang, maka akan ada kesalahan pembulatan ketika angka itu dimasukkan ke dalam struktur data ukuran terbatas yang Anda gunakan. Karena double adalah dua kali ukuran float maka kesalahan pembulatan akan jauh lebih kecil.

Tes dapat secara khusus menggunakan angka yang akan menyebabkan kesalahan semacam ini dan karenanya diuji bahwa Anda telah menggunakan jenis yang sesuai dalam kode Anda.

Dolbz
sumber
9

Tipe float, panjang 32 bit, memiliki ketepatan 7 digit. Meskipun dapat menyimpan nilai dengan rentang yang sangat besar atau sangat kecil (+/- 3.4 * 10 ^ 38 atau * 10 ^ -38), ia hanya memiliki 7 digit signifikan.

Ketik ganda, panjang 64 bit, memiliki jangkauan lebih besar (* 10 ^ + / - 308) dan presisi 15 digit.

Tipe long double secara nominal 80 bit, meskipun pasangan kompiler / OS yang diberikan dapat menyimpannya sebagai 12-16 byte untuk tujuan perataan. Double panjang memiliki eksponen yang luar biasa besar dan memiliki presisi 19 digit. Microsoft, dalam kebijaksanaan mereka yang tak terbatas, membatasi panjang ganda hingga 8 byte, sama dengan ganda biasa.

Secara umum, cukup gunakan tipe ganda ketika Anda membutuhkan nilai / variabel floating point. Nilai floating point literal yang digunakan dalam ekspresi akan diperlakukan sebagai ganda secara default, dan sebagian besar fungsi matematika yang mengembalikan nilai floating point mengembalikan ganda. Anda akan menghemat banyak sakit kepala dan typecasting jika Anda hanya menggunakan ganda.

Zain Ali
sumber
Sebenarnya, untuk float tepatnya antara 7 dan 8, 7.225 tepatnya .
Peter Mortensen
9

Saya hanya mengalami kesalahan yang membutuhkan waktu lama untuk mencari tahu dan berpotensi memberikan Anda contoh presisi mengambang yang baik.

#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;
  }
}

Outputnya adalah

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

Seperti yang Anda lihat setelah 0,83, presisi menurun secara signifikan.

Namun, jika saya atur tdua kali lipat, masalah seperti itu tidak akan terjadi.

Butuh waktu lima jam untuk menyadari kesalahan kecil ini, yang merusak program saya.

Elliscope Fang
sumber
4
hanya untuk memastikan: solusi masalah Anda harus menggunakan int sebaiknya? Jika Anda ingin mengulangi 100 kali, Anda harus menghitung dengan int daripada menggunakan double
BlueTrin
8
Menggunakan doublebukanlah solusi yang baik di sini. Anda menggunakan intuntuk menghitung dan melakukan perkalian internal untuk mendapatkan nilai floating-point Anda.
Richard
3

Saat menggunakan angka floating point Anda tidak dapat mempercayai bahwa tes lokal Anda akan persis sama dengan tes yang dilakukan di sisi server. Lingkungan dan kompiler mungkin berbeda pada sistem lokal Anda dan di mana tes akhir dijalankan. Saya telah melihat masalah ini beberapa kali sebelumnya di beberapa kompetisi TopCoder terutama jika Anda mencoba membandingkan dua angka floating point.

Tuomas Pelkonen
sumber
3

Operasi perbandingan bawaan berbeda seperti ketika Anda membandingkan 2 angka dengan titik mengambang, perbedaan dalam tipe data (yaitu float atau double) dapat menghasilkan hasil yang berbeda.

Johnathan Lau
sumber
1

Jika seseorang bekerja dengan pemrosesan tertanam, pada akhirnya perangkat keras yang mendasarinya (misalnya FPGA atau model prosesor / mikrokontroler tertentu) akan mengapung diimplementasikan secara optimal dalam perangkat keras sedangkan ganda akan menggunakan rutin perangkat lunak. Jadi, jika presisi float cukup untuk menangani kebutuhan, program akan mengeksekusi beberapa kali lebih cepat dengan float kemudian berlipat ganda. Seperti dicatat pada jawaban lain, waspadalah terhadap kesalahan akumulasi.

Lissandro
sumber
-1

Tidak seperti int(bilangan bulat), a floatmemiliki titik desimal, dan begitu juga a double. Tetapi perbedaan antara keduanya adalah bahwa doubledua kali lebih detail dari a float, artinya dapat memiliki dua kali lipat jumlah angka setelah titik desimal.

Nykal
sumber
4
Itu tidak berarti sama sekali. Ini sebenarnya berarti dua kali lebih banyak angka desimal integral , dan lebih dari dua kali lipat. Hubungan antara angka fraksional dan presisi tidak linier: itu tergantung pada nilainya: misalnya 0,5 tepat tetapi 0,33333333333333333333 tidak.
Marquis of Lorne