JavaRush /Blog Jawa /Random-JV /Piranti nomer nyata

Piranti nomer nyata

Diterbitake ing grup
Hello! Wonten ing pawiyatan dinten punika kita badhe ngrembag bab wilangan ing basa Jawi, mliginipun bab wilangan riil. Piranti nomer nyata - 1Aja geger! :) Ora bakal ana kangelan matematika ing kuliah. Kita bakal ngomong babagan nomer nyata mung saka sudut pandang "programmer". Dadi, apa "nomer nyata"? Nomer nyata yaiku nomer sing duwe bagean pecahan (sing bisa dadi nol). Padha bisa positif utawa negatif. Ing ngisor iki sawetara conto: 15 56.22 0.0 1242342343445246 -232336.11 Kepiye carane angka nyata? Cukup prasaja: kasusun saka bagean integer, bagean pecahan lan tandha. Kanggo angka positif tandha biasane ora dituduhake kanthi tegas, nanging kanggo angka negatif dituduhake. Sadurunge, kita nliti kanthi rinci babagan operasi nomer sing bisa ditindakake ing Jawa. Antarane wong-wong mau ana akeh operasi matematika standar - tambahan, subtraction, etc. Ana uga sawetara anyar kanggo sampeyan: contone, seko divisi. Nanging kepiye carane nggarap angka ing komputer? Ing wangun apa sing disimpen ing memori?

Nyimpen nomer nyata ing memori

Aku iku ora bakal nemokake kanggo sampeyan sing nomer bisa dadi gedhe lan cilik :) Padha bisa dibandhingake karo saben liyane. Contone, nomer 100 kurang saka nomer 423324. Apa iki mengaruhi operasi komputer lan program kita? Bener - ya . Saben angka diwakili ing Jawa kanthi sawetara nilai tartamtu :
Jinis Ukuran memori (bit) Range saka nilai
byte 8 bit -128 kanggo 127
short 16 bit -32768 kanggo 32767
char 16 bit integer tanpa tandha sing makili karakter UTF-16 (huruf lan angka)
int 32 bit saka -2147483648 kanggo 2147483647
long 64 bit saka -9223372036854775808 nganti 9223372036854775807
float 32 bit saka 2 -149 kanggo (2-2 -23 ) * 2 127
double 64 bit saka 2 -1074 kanggo (2-2 -52 ) * 2 1023
Dina iki kita bakal ngomong babagan rong jinis pungkasan - floatlan double. Loro-lorone nindakake tugas sing padha - makili nomer pecahan. Dheweke uga asring diarani " nomer titik ngambang" . Elingi istilah iki kanggo masa depan :) Contone, nomer 2.3333 utawa 134.1212121212. Cukup aneh. Sawise kabeh, ternyata ora ana bedane antarane rong jinis kasebut, amarga padha nindakake tugas sing padha? Nanging ana bedane. Pay manungsa waé menyang kolom "ukuran ing memori" ing tabel ndhuwur. Kabeh nomer (lan ora mung nomer - kabeh informasi ing umum) disimpen ing memori komputer ing wangun bit. A bit minangka unit informasi sing paling cilik. Iku cukup prasaja. Sembarang bit padha karo 0 utawa 1. Lan tembung " bit " dhewe asalé saka basa Inggris " digit biner " - nomer biner. Aku sampeyan mbokmenawa wis krungu bab orane sistem bilangan biner ing matematika. Sembarang angka desimal sing kita kenal bisa diwakili minangka set siji lan nol. Contone, angka 584.32 ing binar bakal katon kaya iki: 100100100001010001111 . Saben siji lan nul ing nomer iki dicokot kapisah. Saiki sampeyan kudu luwih jelas babagan bedane antarane jinis data. Contone, yen kita nggawe sawetara jinis float, kita mung duwe 32 bit ing pembuangan kita. Nalika nggawe nomer, floatiki persis carane akeh papan bakal diparengake kanggo ing memori komputer. Yen kita pengin nggawe nomer 123456789.65656565656565, ing binar bakal katon kaya iki: 11101011011110011010001010110101000000 . Iku kasusun saka 38 siji lan nul, yaiku, 38 bit dibutuhake kanggo nyimpen ing memori. floatNomer iki mung ora bakal "pas" menyang jinis ! Mulane, nomer 123456789 bisa dituduhake minangka jinis double. Nganti 64 bit diparengake kanggo nyimpen: iki cocog karo kita! Mesthine, sawetara nilai uga bakal cocog. Kanggo penak, sampeyan bisa mikir nomer minangka kothak cilik karo sel. Yen ana cukup sel kanggo nyimpen saben bit, banjur jinis data dipilih kanthi bener :) Piranti nomer nyata - 2Mesthi, jumlah memori sing diparengake beda uga mengaruhi nomer kasebut dhewe. Wigati dimangerteni manawa jinis floatduwe doublerentang nilai sing beda. Apa tegese iki ing laku? Sawijining angka doublebisa nyebutake presisi sing luwih dhuwur tinimbang angka float. Nomer floating point 32-bit (ing Jawa iki persis jinise float) duwe presisi kira-kira 24 bit, yaiku, kira-kira 7 panggonan desimal. Lan angka 64-bit (ing Jawa iki jinise double) nduweni presisi kira-kira 53 bit, yaiku, kira-kira 16 panggonan desimal. Iki minangka conto sing nuduhake prabédan iki kanthi apik:
public class Main {

   public static void main(String[] args)  {

       float f = 0.0f;
       for (int i=1; i <= 7; i++) {
           f += 0.1111111111111111;
       }

       System.out.println(f);
   }
}
Apa sing kudu ditindakake ing kene? Iku bakal katon yen kabeh iku cukup prasaja. We duwe nomer 0.0, lan kita nambah 0.11111111111111111 kanggo 7 kaping saurutan. Asil kudu 0.777777777777777. Nanging kita nggawe nomer float. Ukurane diwatesi nganti 32 bit lan, kaya sing wis dakkandhakake sadurunge, bisa nampilake angka nganti udakara 7. Mulane, ing pungkasan, asil sing kita entuk ing konsol bakal beda karo sing dikarepake:

0.7777778
Nomer kasebut katon "dipotong". Sampeyan wis ngerti carane data disimpen ing memori - ing wangun bit, supaya iki ora surprise sampeyan. Cetha kenapa iki kedadeyan: asil 0.7777777777777777 mung ora cocog karo 32 bit sing diparengake kanggo kita, mula dipotong supaya pas karo variabel jinis float:) Kita bisa ngganti jinis variabel kasebut doubleing conto kita, banjur pungkasan asil ora bakal dipotong:
public class Main {

   public static void main(String[] args)  {

       double f = 0.0;
       for (int i=1; i <= 7; i++) {
           f += 0.1111111111111111;
       }

       System.out.println(f);
   }
}

0.7777777777777779
Wis ana 16 panggonan desimal, asil "cocog" dadi 64 bit. Ngomong-ngomong, mbok menawa sampeyan ngeweruhi yen ing kasus loro, asil ora bener? Pitungan kasebut digawe kanthi kesalahan cilik. Kita bakal ngomong babagan alasan ing ngisor iki :) Saiki ayo ngomong sawetara tembung babagan carane sampeyan bisa mbandhingake nomer siji liyane.

Perbandingan nomer nyata

Kita sebagian wis ndemek masalah iki ing kuliah pungkasan, nalika kita ngomong babagan operasi perbandingan. Kita ora bakal nganalisa maneh operasi kayata >, <, >=. <=Ayo goleki conto sing luwih menarik tinimbang:
public class Main {

   public static void main(String[] args)  {

       double f = 0.0;
       for (int i=1; i <= 10; i++) {
           f += 0.1;
       }

       System.out.println(f);
   }
}
Apa nomer sampeyan mikir bakal ditampilake ing layar? Jawaban logis bakal dadi jawaban: nomer 1. Kita miwiti ngetang saka nomer 0,0 lan kasil nambah 0,1 kanggo sepuluh kaping saurutan. Kabeh katon bener, kudu dadi siji. Coba mbukak kode iki, lan jawabane bakal kaget banget :) Output konsol:

0.9999999999999999
Nanging kenapa ana kesalahan ing conto sing prasaja? O_o Ing kene malah bocah kelas lima gampang mangsuli kanthi bener, nanging program Jawa ngasilake asil sing ora akurat. Tembung "ora akurat" luwih apik tinimbang "ora bener". Kita isih entuk nomer sing cedhak banget karo siji, lan ora mung sawetara nilai acak :) Iku beda karo sing bener kanthi millimeter. Nanging kenapa? Mbok menawa iki mung kesalahan sepisan. Mungkin komputer nabrak? Ayo coba nulis conto liyane.
public class Main {

   public static void main(String[] args)  {

       //add 0.1 to zero eleven times in a row
       double f1 = 0.0;
       for (int i = 1; i <= 11; i++) {
           f1 += .1;
       }

       // Multiply 0.1 by 11
       double f2 = 0.1 * 11;

       //should be the same - 1.1 in both cases
       System.out.println("f1 = " + f1);
       System.out.println("f2 = " + f2);

       // Let's check!
       if (f1 == f2)
           System.out.println("f1 and f2 are equal!");
       else
           System.out.println("f1 and f2 are not equal!");
   }
}
Output konsol:

f1 = 1.0999999999999999
f2 = 1.1
f1 и f2 не равны!
Dadi, iki jelas dudu masalah komputer :) Apa sing kedadeyan? Kesalahan kaya iki ana hubungane karo cara nomer dituduhake ing wangun binar ing memori komputer. Kasunyatane yaiku ing sistem binar ora bisa kanthi akurat makili angka 0.1 . Miturut cara, sistem desimal uga duwe masalah sing padha: ora mungkin kanggo makili pecahan kanthi bener (lan tinimbang ⅓ kita entuk 0,33333333333333 ..., sing uga ora cukup asil sing bener). Iku bakal katon kaya trifle: karo petungan kuwi, prabédan bisa dadi satus ewu bagean (0,00001) utawa malah kurang. Nanging kepiye yen kabeh asil Program Serius banget gumantung karo perbandingan iki?
if (f1 == f2)
   System.out.println("Rocket flies into space");
else
   System.out.println("The launch is canceled, everyone goes home");
Kita ngarepake kanthi jelas yen rong nomer kasebut padha, nanging amarga desain memori internal, kita mbatalake peluncuran roket. Piranti nomer nyata - 3Yen mangkono, kita kudu mutusake carane mbandhingake rong angka floating-point supaya asil perbandingan kasebut luwih ... ummm ... bisa ditebak. Dadi , kita wis sinau aturan No. == Oke, aku rumangsa cukup conto sing ala :) Ayo goleki conto sing apik!
public class Main {

   public static void main(String[] args)  {

       final double threshold = 0.0001;

       //add 0.1 to zero eleven times in a row
       double f1 = .0;
       for (int i = 1; i <= 11; i++) {
           f1 += .1;
       }

       // Multiply 0.1 by 11
       double f2 = .1 * 11;

       System.out.println("f1 = " + f1);
       System.out.println("f2 = " + f2);

       if (Math.abs(f1 - f2) < threshold)
           System.out.println("f1 and f2 are equal");
       else
           System.out.println("f1 and f2 are not equal");
   }
}
Ing kene kita nindakake perkara sing padha, nanging ngganti cara mbandhingake nomer kasebut. Kita duwe nomer "ambang" khusus - 0,0001, siji sepuluh ewu. Bisa uga beda. Iku gumantung carane pas comparison sampeyan kudu ing kasus tartamtu. Sampeyan bisa nggawe luwih gedhe utawa luwih cilik. Nggunakake metode kasebut, Math.abs()kita entuk modulus nomer. Modulus minangka nilai nomer tanpa preduli saka tandha. Contone, angka -5 lan 5 bakal duwe modulus sing padha lan padha karo 5. Kita nyuda nomer kaloro saka nomer pisanan, lan yen asil asil, preduli saka tandha, kurang saka batesan sing disetel, banjur nomer kita padha. Ing kasus apa wae, padha karo tingkat akurasi sing diadegake kanthi nggunakake "nomer ambang" , yaiku, paling ora padha karo siji sepuluh ewu. Cara mbandhingake iki bakal nylametake sampeyan saka prilaku sing ora dikarepke sing katon ing kasus ==. Cara liya sing apik kanggo mbandhingake nomer nyata yaiku nggunakake kelas khusus BigDecimal. Kelas iki digawe khusus kanggo nyimpen nomer akeh banget karo bagean pecahan. Boten kados doublelan float, nalika nggunakake BigDecimaltambahan, subtraction lan operasi matematika liyane dileksanakake ora nggunakake operator ( +-, etc.), nanging nggunakake cara. Iki bakal katon kaya ing kasus kita:
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args)  {

       /*Create two BigDecimal objects - zero and 0.1.
       We do the same thing as before - add 0.1 to zero 11 times in a row
       In the BigDecimal class, addition is done using the add () method */
       BigDecimal f1 = new BigDecimal(0.0);
       BigDecimal pointOne = new BigDecimal(0.1);
       for (int i = 1; i <= 11; i++) {
           f1 = f1.add(pointOne);
       }

       /*Nothing has changed here either: create two BigDecimal objects
       and multiply 0.1 by 11
       In the BigDecimal class, multiplication is done using the multiply() method*/
       BigDecimal f2 = new BigDecimal(0.1);
       BigDecimal eleven = new BigDecimal(11);
       f2 = f2.multiply(eleven);

       System.out.println("f1 = " + f1);
       System.out.println("f2 = " + f2);

       /*Another feature of BigDecimal is that number objects need to be compared with each other
       using the special compareTo() method*/
       if (f1.compareTo(f2) == 0)
           System.out.println("f1 and f2 are equal");
       else
           System.out.println("f1 and f2 are not equal");
   }
}
Apa jenis output console sing bakal kita entuk?

f1 = 1.1000000000000000610622663543836097232997417449951171875
f2 = 1.1000000000000000610622663543836097232997417449951171875
f1 и f2 равны
Kita entuk asil sing dikarepake. Lan mbayar manungsa waé kanggo carane akurat nomer kita nguripake metu, lan carane akeh panggonan desimal pas menyang wong-wong mau! Luwih akeh tinimbang ing floatlan malah ing double! Elingi kelas BigDecimalkanggo masa depan, sampeyan mesthi butuh :) Phew! Kuliah kasebut cukup suwe, nanging sampeyan nindakake: apik! :) Sampai ketemu ing pelajaran sabanjure, programmer mangsa!
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION