Salam! Şu günki leksiýamyzda Java-daky sanlar we esasanam hakyky sanlar barada gürleşeris. Aljyrama! :) Leksiýada matematiki kynçylyklar bolmaz. Hakyky sanlar hakda diňe “programmist” nukdaýnazaryndan gürleşeris. Onda “hakyky sanlar” näme? Hakyky sanlar fraksiýa bölegi bolan sanlardyr (nol bolup biler). Oňyn ýa-da otrisatel bolup biler. Ine käbir mysallar: 15 56.22 0.0 1242342343445246 -232336.11 Hakyky san nähili işleýär? Örän ýönekeý: bitewi bölekden, bölek bölekden we alamatdan ybarat. Oňyn sanlar üçin alamat adatça aç-açan görkezilmeýär, ýöne otrisatel sanlar üçin görkezilýär. Mundan ozal, Java-da sanlar boýunça haýsy amallary ýerine ýetirip boljakdygyny jikme-jik gözden geçirdik . Olaryň arasynda köp sanly matematiki amallar - goşmak, aýyrmak we ş.m. Siziň üçin käbir täzeleri hem bardy: mysal üçin bölünişigiň galan bölegi. Numbersöne sanlar bilen işlemek kompýuteriň içinde nädip işleýär? Haýsy görnüşde ýatda saklanýar?
Bu gün soňky iki görnüş hakda gürleşeris -
Hakyky sanlary ýatda saklamak
Sanlaryň uly we kiçi bolup biljekdigi siziň üçin açyş bolmaz diýip pikir edýärin :) Olary biri-biri bilen deňeşdirip bolar. Mysal üçin, 100 sany 423324 belgiden az. Bu kompýuteriň we programmamyzyň işleýşine täsir edýärmi? Aslynda - hawa . Her san Java-da belli bir bahalar bilen görkezilýär :Görnüşi | Oryadyň ululygy (bitler) | Gymmatlyklaryň diapazony |
---|---|---|
byte |
8 bit | -128-den 127-e çenli |
short |
16 bit | -32768-den 32767-e çenli |
char |
16 bit | UTF-16 nyşany (harplar we sanlar) aňladýan gol çekilmedik bitewi san |
int |
32 bit | -2147483648-den 2147483647-e çenli |
long |
64 bit | -9223372036854775808-den 9223372036854775807-e çenli |
float |
32 bit | 2 -149- dan (2-2 -23 ) * 2 127-e çenli |
double |
64 bit | 2 -1074 -den (2-2 -52 ) * 2 1023-e çenli |
float
we double
. Ikisi-de birmeňzeş işi ýerine ýetirýärler - fraksiýa sanlaryny görkezýärler. Olara köplenç “ ýüzýän nokat sanlary” diýilýär . Geljek üçin bu termini ýadyňyzda saklaň :) Mysal üçin, 2.3333 ýa-da 134.1212121212 belgisi. Gaty geň. Galyberse-de, şol bir işi ýerine ýetirýändikleri üçin bu iki görnüşiň arasynda hiç hili tapawut ýokmy? Emma tapawut bar. Aboveokardaky tablisadaky “ýadyň ululygy” sütünine üns beriň. Numbershli sanlar (we diňe sanlar däl - umuman ähli maglumatlar) kompýuter ýadynda bit görnüşinde saklanýar. Biraz maglumatyň iň kiçi birligi. Bu gaty ýönekeý. Islendik bit 0 ýa-da 1-e deňdir we “ bit ” sözüniň özi iňlis dilindäki “ ikilik san ” - ikilik belgiden gelýär. Meniň pikirimçe, matematikada ikilik san ulgamynyň barlygy hakda eşiden bolsaňyz gerek. Biziň bilen tanyş bolan islendik onluk san sanlaryň we nollaryň toplumy hökmünde görkezilip bilner. Mysal üçin, ikilikdäki 584.32 belgisi şeýle bolar: 100100100001010001111 . Bu sanyň her biri we noly aýratyn. Indi maglumat görnüşleriniň arasyndaky tapawut barada has aýdyň bolmaly. Mysal üçin, birnäçe görnüşi döreden bolsak float
, diňe 32 bit bar. San döredilende, float
kompýuteriň ýadynda onuň üçin näçeräk ýer bölünjekdigi hut şu. 123456789.6565656565656565 belgisini döretmek islesek, ikilik görnüşinde şeýle bolar : 11101011011110011010001010110101000000 38 we noldan ybarat, ýagny ýatda saklamak üçin 38 bit gerek. Bu san görnüşine float
“laýyk gelmez” ! Şonuň üçin 123456789 belgisini bir görnüş hökmünde görkezip bolýar double
. Saklamak üçin 64 bit bölünip berilýär: bu bize laýyk gelýär! Elbetde, gymmatlyklaryň diapazony hem amatly bolar. Amatly bolmak üçin, sanlary öýjükler bilen kiçijik guty diýip pikir edip bilersiňiz. Her biti saklamak üçin ýeterlik öýjük bar bolsa, maglumatlaryň görnüşi dogry saýlanýar :) Elbetde, bölünen ýadyň dürli mukdary hem sanyň özüne täsir edýär. Görnüşleriň dürli bahalaryň float
bardygyny ýadyňyzdan çykarmaň. double
Iş ýüzünde bu nämäni aňladýar? San double
sanlardan has takyklygy görkezip biler float
. 32 bitli ýüzýän nokat sanlary (Java-da bu görnüşiň görnüşi float
) takmynan 24 bit, ýagny 7 onluk ýer takyklygy bar. 64 bitli sanlar (Java-da bu görnüş double
) takmynan 53 bit, ýagny takmynan 16 onluk ýer bar. Ine, bu tapawudy gowy görkezýän mysal:
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);
}
}
Netijede bu ýere näme almaly? Hemme zat gaty ýönekeý ýaly. Bizde 0.0 belgisi bar we oňa yzly-yzyna 7 gezek 0.111111111111111111 goşýarys. Netije 0.7777777777777777 bolmaly. Emma san döretdik float
. Onuň ululygy 32 bit bilen çäklenýär we öňem aýdyşymyz ýaly, takmynan 7-nji onluk ýere çenli san görkezmäge ukyply. Şonuň üçin ahyrynda konsolda alýan netijämiz garaşyşymyzdan tapawutly bolar:
0.7777778
Bu san “kesilen” ýalydy. Maglumatlaryň ýatda nähili saklanýandygyny eýýäm bilýärsiňiz - bit görnüşinde, bu sizi geň galdyrmaly däldir. Munuň näme üçin bolup geçendigi düşnüklidir: 0.7777777777777777 netijesi diňe bize bölünen 32 bit bilen gabat gelmedi, şonuň üçin görnüş üýtgeýjisine gabat gelmek üçin kesildi float
:) Üýtgeýjiniň görnüşini double
mysalymyzda üýtgedip bileris, soň bolsa jemleýji netije kesilmez:
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
Eýýäm 16 onluk ýer bar, netijesi 64 bite “laýyk gelýär”. Theeri gelende aýtsak, iki ýagdaýda-da netijeleriň düýbünden dogry däldigine göz ýetirdiňiz? Hasap ownuk ýalňyşlyklar bilen geçirildi. Munuň sebäpleri barada aşakda gürleşeris :) Indi sanlary biri-biri bilen nädip deňeşdirip boljakdygy barada birnäçe söz aýdalyň.
Hakyky sanlary deňeşdirmek
Geçen leksiýada deňeşdirme amallary barada aýdanymyzda, bu meselä bölekleýin degip geçdik.>
,,, operationsaly amallary täzeden seljeremzok <
. Munuň ýerine has gyzykly mysala seredeliň: >=
<=
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);
}
}
Siziň pikiriňizçe ekranda haýsy nomer görkeziler? Mantykly jogap jogap bolar: 1-nji san. 0.0 belgisinden sanap başlaýarys we yzly-yzyna on gezek 0,1 goşýarys. Hemme zat dogry ýaly, bir bolmaly. Bu kody işledip görüň, jogap sizi gaty geň galdyrar :) Konsol çykyşy:
0.9999999999999999
Emma näme üçin beýle ýönekeý mysalda ýalňyşlyk ýüze çykdy? O_o Bu ýerde hatda bäşinji synp okuwçysy hem aňsatlyk bilen dogry jogap berip bilerdi, ýöne Java programmasy nädogry netije berdi. “Nädogry” bu ýerde “nädogry” sözlerden has gowy söz. Diňe bir tötänleýin baha däl-de, birine gaty ýakyn bir san aldyk :) Dogrysyndan millimetr bilen tapawutlanýar. Emma näme üçin? Belki, bu diňe bir gezeklik ýalňyşlykdyr. Belki, kompýuter ýykyldy? Başga bir mysal ýazmaga synanyşalyň.
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!");
}
}
Konsol çykyşy:
f1 = 1.0999999999999999
f2 = 1.1
f1 и f2 не равны!
Diýmek, bu kompýuteriň ýalňyşlygy däl. Näme bolýar? Rorsalňyşlyklaryň bu görnüşleri, sanlaryň kompýuteriň ýadynda ikilik görnüşde görkezilişi bilen baglanyşyklydyr. Hakykat, ikilik ulgamynda 0,1 belgini takyk görkezmek mümkin däl . Theeri gelende aýtsak, onluk ulgamyň hem şuňa meňzeş meselesi bar: fraksiýalary dogry görkezmek mümkin däl (we instead ýerine 0.3333333333333333 alarys ... bu hem dogry netije däl). Bu ownuk-uşak ýaly bolup görünýär: şeýle hasaplamalar bilen tapawut ýüz müňden bir bölegi (0,00001) ýa-da ondanam az bolup biler. Veryöne gaty çynlakaý programmaňyzyň netijesi bu deňeşdirmä bagly bolsa näme etmeli?
if (f1 == f2)
System.out.println("Rocket flies into space");
else
System.out.println("The launch is canceled, everyone goes home");
Iki sanyň deň boljakdygyna aç-açan garaşýardyk, ýöne içerki ýat dizaýny sebäpli raketa atyşyny ýatyrdyk. Şeýle bolsa, deňeşdirmegiň netijesi has ... ummm ... öňünden aýdyp bolar ýaly iki ýüzýän nokat sanyny nädip deňeşdirmelidigini çözmeli. Şeýlelik bilen, hakyky sanlary deňeşdirenimizde eýýäm 1-nji düzgüni öwrendik: hakyky sanlar bilen deňeşdirilende hiç haçan ýüzýän nokat sanlaryny ulanmaň . ==
Bolýar, bu ýeterlik erbet mysallardyr öýdýän :) Gowy mysal göreliň!
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");
}
}
Bu ýerde aslynda şol bir zady edýäris, ýöne sanlary deňeşdirmegiň usulyny üýtgedýäris. Bizde ýörite “bosagada” san bar - 0.0001, on müňden bir. Başgaça bolup biler. Belli bir ýagdaýda deňeşdirmegiň näderejede takykdygyna baglydyr. Uly ýa-da kiçi edip bilersiňiz. Usuly ulanyp, Math.abs()
sanyň modulyny alýarys. Modul, belgä garamazdan sanyň bahasydyr. Mysal üçin, -5 we 5 sanlaryň birmeňzeş moduly bolar we 5-e deň bolar. Ikinji belgini birinjisinden aýyrarys, eger netijä, belgä garamazdan, bellenen çäkden az bolsa, onda sanlarymyz deňdir. Her niçigem bolsa, olar “çäk belgimizi” ulanyp kesgitlän takyklyk derejämize deňdir , ýagny iň bolmanda on müňden birine deňdir. Deňeşdirmegiň bu usuly sizi gören garaşylmadyk hereketlerden halas eder ==
. Hakyky sanlary deňeşdirmegiň ýene bir gowy usuly, ýörite synp ulanmakdyr BigDecimal
. Bu synp bölekleýin bölegi bilen gaty köp sanly saklamak üçin ýörite döredildi. double
Goşmaçadan tapawutlylykda float
, BigDecimal
aýyrmak we beýleki matematiki amallar operatorlary (we ş.m.) ulanman +-
, usullary ulanmak arkaly ýerine ýetirilýär. Bu biziň ýagdaýymyzda nähili bolar:
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");
}
}
Haýsy konsol çykyşyny alarys?
f1 = 1.1000000000000000610622663543836097232997417449951171875
f2 = 1.1000000000000000610622663543836097232997417449951171875
f1 и f2 равны
Biz garaşýan netijämizi aldyk. Sanlarymyzyň näderejede dogry çykandygyna we näçe onluk ýerlere laýyk gelýändigine üns beriň! float
Içinden we hatda has köp zat double
! BigDecimal
Geljek üçin synpy ýadyňyzda saklaň , hökman size gerek bolar :) Phew! Leksiýa gaty uzyn, ýöne muny etdiň: gowy! :) Geljekki programmist, indiki sapakda görüşeris!
GO TO FULL VERSION