I'telah membaca tentang perbedaan antara double presisi tunggal dan presisi. Namun, dalam kebanyakan kasus, mengambang
dan double
tampaknya akan dipertukarkan, yaitu menggunakan satu atau yang lain tampaknya tidak mempengaruhi hasil. Ini benar-benar terjadi? Ketika mengapung dan berfungsi dipertukarkan? Apa perbedaan antara mereka?
Perbedaan besar.
Seperti namanya, sebuah dua
memiliki 2x presisi float
[1]. Secara umum yang double
memiliki 15 digit desimal presisi, sementara float
memiliki 7.
Berikut ini's berapa jumlah digit dihitung:
ganda
ini memiliki 52 bit mantissa + 1 hidden bit: log(253)÷log(10) = 15.95 digit
float
memiliki 23 bit mantissa + 1 hidden bit: log(224)÷log(10) = 7.22 digit
Presisi ini kerugian besar dapat menyebabkan pemotongan galat yang terakumulasi ketika diulang perhitungan yang 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 dari float adalah tentang 3e38
, tapi ganda tentang 1.7e308
, jadi menggunakan float
dapat menekan "infinity" (yaitu khusus floating-point number) jauh lebih mudah daripada double
untuk sesuatu yang sederhana, misalnya menghitung faktorial dari 60.
Selama pengujian, mungkin beberapa kasus uji ini mengandung jumlah besar, yang dapat menyebabkan program anda gagal jika anda menggunakan pelampung.
Tentu saja, kadang-kadang, bahkan double
isn't cukup akurat, maka kita kadang-kadang memiliki long double
[1] (contoh di atas memberikan 9.000000000000000066 pada Mac), tapi semua floating point tipe menderita round-off errors, jadi jika presisi sangat penting (misalnya pengolahan uang) anda harus menggunakan int
atau pecahan kelas.
Selain itu, don't menggunakan +=
untuk jumlah banyak dari angka floating point, seperti kesalahan-kesalahan yang menumpuk dengan cepat. Jika anda're menggunakan Python, menggunakan fsum
. Jika tidak, cobalah untuk menerapkan Kahan algoritma penjumlahan.
[1]: C dan C++ standar tidak menentukan representasi dari mengambang
, double
dan long double
. Adalah mungkin bahwa semua tiga diimplementasikan sebagai IEEE double-precision. Namun demikian, untuk sebagian besar arsitektur (gcc, MSVC; x86, x64, LENGAN) float
adalah memang IEEE single-precision floating point number (binary32), dan double
adalah IEEE double-precision floating point number (binary64).
Berikut adalah apa yang standar C99 (ISO-IEC 9899 6.2.5 §10) atau C++2003 (ISO-IEC 14882-2003 3.1.9 §8) standar berkata:
Ada tiga titik mengambang jenis:
mengambang
,dua
, danlong double
. Jenisdouble
menyediakan setidaknya sebanyak presisi sepertimengambang
danlong double
menyediakan setidaknya presisi sebanyakganda
. Set nilai-nilai dari tipe yangmengambang
adalah subset dari himpunan nilai-nilai dari tipe yangdouble
; set nilai-nilai dari tipe yangdouble
adalah subset dari himpunan nilai-nilai dari tipelong double
.
Standar C++ menambahkan:
nilai representasi floating-point jenis adalah pelaksanaan yang ditetapkan.
Saya akan menyarankan untuk memiliki melihat pada setiap Apa yang Setiap Ilmuwan Komputer Harus Tahu Tentang Floating-Point Aritmatika yang mencakup IEEE floating-point standar di kedalaman. Anda'll belajar tentang representasi rincian dan anda'll menyadari ada tradeoff antara besarnya dan presisi. Presisi floating point representasi meningkat seiring besarnya menurun, maka angka floating point antara -1 dan 1 adalah mereka yang paling presisi.
Diberikan persamaan kuadrat: x2 − 4.0000000 x + 3.9999999 = 0, tepat akar ke 10 digit yang signifikan adalah, r1 = 2.000316228 dan r2 = 1.999683772.
Menggunakan mengambang
dan double
, kita dapat menulis sebuah program uji:
#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 ini memberikan saya:
2.00000 2.00000
2.00032 1.99968
Perhatikan bahwa angka-angka aren't besar, tetapi anda masih mendapatkan efek pembatalan menggunakan mengapung
.
(Pada kenyataannya, di atas adalah bukan cara terbaik untuk menyelesaikan persamaan kuadrat dengan menggunakan single atau double - presisi floating-point numbers, tapi jawabannya tetap tidak berubah bahkan jika seseorang menggunakan lebih stabil metode.)
Ukuran angka-angka yang terlibat di lampung-titik perhitungan bukan yang paling penting. It's perhitungan yang sedang dilakukan yang relevan.
Pada dasarnya, jika anda're melakukan perhitungan dan hasilnya adalah nomor irasional atau berulang desimal, maka akan ada kesalahan pembulatan ketika nomor yang tergencet dalam ukuran terbatas struktur data anda're menggunakan. Sejak ganda adalah dua kali ukuran float maka kesalahan pembulatan akan menjadi jauh lebih kecil.
Tes mungkin secara khusus menggunakan angka yang akan menyebabkan kesalahan semacam ini dan oleh karena itu diuji bahwa anda'd digunakan jenis yang tepat dalam kode anda.
Tipe float, 32 bit, memiliki ketepatan 7 digit. Sementara itu mungkin menyimpan nilai yang sangat besar atau sangat kecil (+/- 3.4 10^38 atau 10^-38), hanya memiliki 7 digit yang signifikan.
Tipe double, 64 bit, memiliki rentang yang lebih besar (*10^+/-308) dan 15 digit presisi.
Jenis long double nominal 80 bit, meskipun diberikan compiler/OS pasangan dapat menyimpannya sebagai 12-16 byte untuk keselarasan tujuan. Panjang ganda memiliki eksponen yang hanya ridiculously besar dan harus memiliki 19 digit presisi. Microsoft, dalam kebijaksanaan yang tak terbatas, batas panjang double 8 byte, sama seperti yang polos double.
Secara umum, hanya menggunakan tipe double ketika anda membutuhkan sebuah nilai floating point/variabel. Literal floating point nilai-nilai yang digunakan dalam ekspresi akan diperlakukan sebagai ganda secara default, dan sebagian besar matematika fungsi-fungsi yang mengembalikan nilai-nilai floating point kembali berfungsi. Anda'akan menghemat banyak sakit kepala dan typecastings jika anda hanya menggunakan double.
Aku hanya berlari ke sebuah kesalahan yang membawa saya selamanya untuk mengetahui dan berpotensi dapat memberikan sebuah contoh yang baik dari mengapung presisi.
#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;
}
}
Output 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 berjalan turun secara signifikan.
Namun, jika saya set up t
sebagai ganda, seperti masalah won't terjadi.
Butuh waktu lima jam untuk menyadari hal ini kesalahan kecil, yang merusak program saya.
Ketika menggunakan angka floating point anda tidak percaya bahwa anda tes lokal akan persis sama seperti tes yang dilakukan pada sisi server. Lingkungan dan compiler yang mungkin berbeda pada sistem lokal anda dan di mana tes akhir yang menjalankan. Saya telah melihat masalah ini berkali-kali dalam beberapa kompetisi TopCoder terutama jika anda mencoba untuk membandingkan dua angka floating point.
Built-in perbandingan operasi berbeda seperti ketika anda membandingkan 2 angka dengan floating point, perbedaan jenis data (yaitu float atau double) dapat mengakibatkan hasil yang berbeda.
Tidak seperti sebuah int
(angka penuh), yang mengapung
memiliki titik desimal, dan agar bisa double
.
Namun perbedaan antara keduanya adalah bahwa yang double
adalah dua kali lebih rinci sebagai mengambang
, yang berarti bahwa hal itu dapat memiliki dua kali lipat jumlah angka setelah titik desimal.