JavaRush /Блоги Java /Random-TG /Дастгоҳи рақамҳои воқеӣ

Дастгоҳи рақамҳои воқеӣ

Дар гурӯҳ нашр шудааст
Салом! Дар лексияи имрӯза мо дар бораи рақамҳо дар Java ва махсусан дар бораи рақамҳои воқеӣ сӯҳбат хоҳем кард. Дастгоҳи рақамҳои воқеӣ - 1Хуруҷи воҳима! :) Дар лекция ягон душвории математики пеш намеояд. Мо дар бораи рақамҳои воқеӣ танҳо аз нуқтаи назари "барномасоз" сӯҳбат хоҳем кард. Пас, "рақамҳои воқеӣ" чист? Рақамҳои воқеӣ ададҳое мебошанд, ки қисми касрӣ доранд (ки метавонад сифр бошад). Онҳо метавонанд мусбат ё манфӣ бошанд. Инак чанд мисол: 15 56,22 0,0 1242342343445246 -232336,11 Шумораи воқеӣ чӣ гуна кор мекунад? Хеле оддӣ: он аз қисми бутун, қисми касрӣ ва аломат иборат аст. Барои рақамҳои мусбӣ аломат одатан ба таври возеҳ нишон дода намешавад, аммо барои рақамҳои манфӣ он нишон дода мешавад. Пештар мо муфассал дида баромадем , ки дар Java кадом амалҳоро бо рақамҳо иҷро кардан мумкин аст. Дар байни онҳо бисёр амалҳои математикии стандартӣ - ҷамъ кардан, тарҳ кардан ва ғайра буданд. Барои шумо якчанд амалҳои нав низ буданд: масалан, боқимондаи тақсим. Аммо кор бо рақамҳо дар дохor компютер чӣ гуна кор мекунад? Онҳо дар кадом шакл дар хотира нигоҳ дошта мешаванд?

Нигоҳ доштани рақамҳои воқеӣ дар хотира

Ман фикр мекунам, ки ин барои шумо кашфиёт нахоҳад буд, ки рақамҳо метавонанд калон ва хурд бошанд :) Онҳоро метавон бо ҳамдигар муқоиса кард. Масалан, рақами 100 аз рақами 423324 камтар аст. Оё ин ба кори компютер ва барномаи мо таъсир мерасонад? Дар асл - ҳа . Ҳар як рақам дар Java бо доираи муайяни арзишҳо ифода карда мешавад :
Навъи Андозаи хотира (бит) Диапазони арзишҳо
byte 8 бит -128 ба 127
short 16 бит -32768 ба 32767
char 16 бит адади беимзо, ки аломати UTF-16-ро ифода мекунад (ҳарфҳо ва рақамҳо)
int 32 бит аз -2147483648 то 2147483647
long 64 бит аз -9223372036854775808 то 9223372036854775807
float 32 бит аз 2 -149 то (2-2 -23 )*2 127
double 64 бит аз 2 -1074 то (2-2 -52 )*2 1023
Имрӯз мо дар бораи ду намуди охирин сӯҳбат хоҳем кард - floatва double. Ҳарду як вазифаро иҷро мекунанд - ифода кардани рақамҳои касрӣ. Онҳо инчунин аксар вақт " рақамҳои нуқтаи шинокунанда" номида мешаванд . Ин истилоҳро барои оянда дар хотир нигоҳ доред :) Масалан, рақами 2.3333 ё 134.1212121212. Хеле аҷиб. Баъд аз ҳама, маълум мешавад, ки байни ин ду намуд фарқият вуҷуд надорад, зеро онҳо як вазифаро иҷро мекунанд? Аммо фарқият вуҷуд дорад. Ба сутуни "андоза дар хотира" дар ҷадвали боло диққат диҳед. Ҳама рақамҳо (на танҳо рақамҳо - ҳама маълумот дар маҷмӯъ) дар хотираи компютер дар шакли битҳо нигоҳ дошта мешаванд. Бит хурдтарин воҳиди иттилоот аст. Ин хеле содда аст. Ҳар як бит ба 0 ё 1 баробар аст. Ва худи калимаи “ bit ” аз забони англисӣ “ binary digit ” - рақами дуӣ меояд. Ман фикр мекунам, ки шумо эҳтимол дар бораи мавҷудияти системаи рақамҳои дуӣ дар математика шунидаед. Ҳар як адади даҳӣ, ки мо бо онҳо шинос ҳастем, метавонад ҳамчун маҷмӯи якҳо ва сифрҳо ифода карда шавад. Масалан, рақами 584.32 дар дуӣ чунин хоҳад буд: 100100100001010001111 . Ҳар як ва сифр дар ин рақам як битҳои алоҳида аст. Акнун шумо бояд дар бораи фарқияти байни намудҳои маълумот равшантар бошед. Масалан, агар мо як қатор навъи ро эҷод кунем float, мо танҳо 32 бит дар ихтиёр дорем. Ҳангоми сохтани адад floatмаҳз ҳамин тавр дар хотираи компютер барои он чӣ қадар ҷой ҷудо карда мешавад. Агар мо хоҳем, ки рақами 123456789.65656565656565-ро созем, дар дуӣ он чунин хоҳад буд: 11101011011110011010001010110101000000 . Он аз 38 як ва сифр иборат аст, яъне барои дар хотира нигоҳ доштани он 38 бит лозим аст. Ин рақам танҳо ба намуди float"мувофиқ" нахоҳад шуд ! Аз ин рӯ, рақами 123456789 метавонад ҳамчун навъи double. Барои нигоҳ доштани он 64 бит ҷудо карда шудааст: ин ба мо мувофиқ аст! Албатта, доираи арзишҳо низ мувофиқ хоҳад буд. Барои роҳат шумо метавонед рақамро ҳамчун қуттии хурд бо ҳуҷайраҳо тасаввур кунед. Агар барои нигоҳ доштани ҳар як бит ячейкаҳои кофӣ мавҷуд бошанд, он гоҳ навъи маълумот дуруст интихоб карда мешавад :) Дастгоҳи рақамҳои воқеӣ - 2Албатта, миқдори гуногуни хотираи ҷудошуда ба худи рақам низ таъсир мерасонад. Лутфан қайд кунед, ки намудҳо диапазони арзишҳои гуногун floatдоранд . doubleИн дар амал чй маъно дорад? Рақам doubleметавонад нисбат ба рақам дақиқтарро ифода кунад float. Рақамҳои нуқтаи шинокунандаи 32-бит (дар Java ин маҳз навъи float) дақиқии тақрибан 24 бит доранд, яъне тақрибан 7 адад. Ва рақамҳои 64-битӣ (дар Java ин навъ аст double) дақиқии тақрибан 53 бит доранд, яъне тақрибан 16 адад. Ин аст мисоле, ки ин фарқиятро хуб нишон медиҳад:
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);
   }
}
Дар натиҷа мо бояд дар ин ҷо чӣ ба даст орем? Чунин ба назар мерасад, ки ҳама чиз хеле оддӣ аст. Мо рақами 0,0 дорем ва ба он 7 маротиба пай дар пай 0,1111111111111111 илова мекунем. Натиҷа бояд 0,777777777777777 бошад. Аммо мо як рақам эҷод кардем float. Андозаи он бо 32 бит маҳдуд аст ва тавре ки мо қаблан гуфта будем, он қодир аст ададро то тақрибан 7-уми адад нишон диҳад. Аз ин рӯ, дар ниҳоят, натиҷае, ки мо дар консол мегирем, аз он чизе ки мо интизор будем, фарқ мекунад:

0.7777778
Чунин ба назар мерасид, ки рақам "бурида" аст. Шумо аллакай медонед, ки маълумот дар хотира чӣ гуна нигоҳ дошта мешавад - дар шакли бит, аз ин рӯ ин набояд шуморо ба ҳайрат оварад. Маълум аст, ки чаро ин тавр шуд: натиҷа 0.777777777777777 ба 32 битҳои барои мо ҷудошуда мувофиқат намекард, бинобар ин он бурида шуд, то ба тағирёбандаи навъи мувофиқат кунад float:) doubleнатиҷа қатъ карда намешавад:
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
Аллакай 16 адади даҳӣ вуҷуд дорад, натиҷа ба 64 бит "мувофиқ" мешавад. Дар омади гап, шояд шумо пай бурдед, ки дар ҳарду ҳолат натиҷаҳо комилан дуруст нестанд? Ҳисоб бо хатогиҳои хурд анҷом дода шуд. Мо дар зер дар бораи сабабҳои ин гап мезанем :) Акнун биёед чанд сухан дар бораи он ки чӣ тавр шумо метавонед рақамҳоро бо ҳамдигар муқоиса кунед.

Муқоисаи ададҳои воқеӣ

Мо дар лекцияи гузашта, вакте ки дар бораи амалиёти мукоиса сухан ронда будем, ба ин масъала кисман дахл карда будем. Мо амалиётҳоеро аз қабor >, <, , дубора таҳлил намекунем >=. <=Биёед ба ҷои мисоли ҷолибтарро бубинем:
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);
   }
}
Ба фикри шумо кадом рақам дар экран нишон дода мешавад? Ҷавоби мантиқӣ ҷавоб хоҳад буд: рақами 1. Мо аз рақами 0,0 ҳисоб карданро оғоз мекунем ва ба он пай дар пай даҳ маротиба 0,1 илова мекунем. Ҳама чиз дуруст ба назар мерасад, он бояд як бошад. Кӯшиш кунед, ки ин codeро иҷро кунед ва ҷавоб шуморо ба ҳайрат меорад :) Натиҷаи консол:

0.9999999999999999
Аммо чаро дар чунин мисоли оддие хато рух дод? O_o Дар ин ҷо ҳатто хонандаи синфи панҷум метавонад ба осонӣ ҷавоби дуруст диҳад, аммо барномаи Java натиҷаи нодуруст дод. Дар ин ҷо калимаи "нодуруст" беҳтар аз "нодуруст" аст. Мо то ҳол рақами хеле наздик ба як гирифтем, на танҳо ягон арзиши тасодуфӣ :) Он аз рақами дуруст аслан як миллиметр фарқ мекунад. Аммо барои чӣ? Шояд ин як хатогии якдафъаина бошад. Шояд компютер шикаста бошад? Биёед кӯшиш кунем, ки мисоли дигар нависем.
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!");
   }
}
Натиҷаи консол:

f1 = 1.0999999999999999
f2 = 1.1
f1 и f2 не равны!
Пас, ин бешубҳа масъалаи норасоиҳои компютер нест :) Чӣ мешавад? Хатогиҳои ба ин монанд ба тарзи дар хотираи компютер дар шакли дуӣ нишон додани рақамҳо алоқаманданд. Гап дар он аст, ки дар системаи дуӣ рақами 0,1-ро дақиқ ифода кардан ғайриимкон аст . Дар омади гап, дар системаи даҳӣ низ чунин мушкилот вуҷуд дорад: дуруст ифода кардани каср ғайриимкон аст (ва ба ҷои ⅓ мо 0,33333333333333... мегирем, ки ин ҳам натиҷаи дуруст нест). Ин як чизи ночиз ба назар мерасад: бо чунин ҳисобҳо фарқият метавонад як қисми сад ҳазорум (0,00001) ё ҳатто камтар бошад. Аммо чӣ мешавад, агар тамоми натиҷаи барномаи хеле ҷиддии шумо аз ин муқоиса вобаста бошад?
if (f1 == f2)
   System.out.println("Rocket flies into space");
else
   System.out.println("The launch is canceled, everyone goes home");
Мо ба таври возеҳ интизор будем, ки ду рақам баробаранд, аммо аз сабаби тарҳрезии хотираи дохилӣ мо партоби мушакро лағв кардем. Дастгоҳи рақамҳои воқеӣ - 3Агар ин тавр бошад, мо бояд тасмим гирем, ки чӣ гуна ду рақами шинокунандаи нуқтаро муқоиса кунем, то натиҷаи муқоиса бештар... ммм... пешгӯӣ шавад. Ҳамин тавр, мо аллакай қоидаи №1-ро ҳангоми муқоисаи ададҳои воқеӣ омӯхтем: ҳеҷ гоҳ ҳангоми муқоисаи ададҳои воқеӣ рақамҳои шинокунандаро истифода набаред . == Хуб, ман фикр мекунам, ки ин мисолҳои бад кофӣ аст :) Биёед як мисоли хубро бубинем!
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");
   }
}
Дар ин ҷо мо аслан ҳамин корро мекунем, аммо тарзи муқоисаи рақамҳоро тағир медиҳем. Мо рақами махсуси «остона» дорем - 0,0001, як даҳ ҳазор. Он метавонад гуногун бошад. Ин аз он вобаста аст, ки то чӣ андоза ба шумо дар мавриди мушаххас муқоиса лозим аст. Шумо метавонед онро калонтар ё хурдтар созед. Бо истифода аз усул Math.abs()мо модули ададро мегирем. Модул арзиши адад аст, новобаста аз аломати. Масалан, ададњои -5 ва 5 модули якхела доранд ва ба 5 баробар мешаванд. Мо адади дуюмро аз аввал хориљ мекунем ва агар натиљаи њосилшуда, новобаста аз нишона, аз њадди муќарраркардаи мо камтар бошад, пас шумораи мо баробар аст. Дар ҳар сурат, онҳо ба дараҷаи дақиқе, ки мо бо истифода аз "рақами остона"-и худ муқаррар кардем , баробаранд, яъне ҳадди ақалл ба даҳҳазорӣ баробаранд. Ин усули муқоиса шуморо аз рафтори ғайричашмдошт, ки мо дар мавриди ==. Дигар роҳи хуби муқоисаи рақамҳои воқеӣ ин истифодаи синфи махсус аст BigDecimal. Ин синф махсусан барои нигоҳ доштани ададҳои хеле калон бо қисми касрӣ сохта шудааст. Баръакси doubleва float, ҳангоми истифодаи ҷамъ, тарҳ ва дигар амалҳои математикӣ на бо истифода аз операторҳо ( , ва ғ.), балки бо истифода аз усулҳо BigDecimalиҷро карда мешаванд . +-Ин дар ҳолати мо чунин хоҳад буд:
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");
   }
}
Мо чӣ гуна баромади консол мегирем?

f1 = 1.1000000000000000610622663543836097232997417449951171875
f2 = 1.1000000000000000610622663543836097232997417449951171875
f1 и f2 равны
Мо маҳз натиҷаи интизориамонро гирифтем. Ва диққат диҳед, ки рақамҳои мо то чӣ андоза дақиқ буданд ва ба онҳо чӣ қадар шумораи даҳӣ мувофиқат мекунанд! Хеле бештар аз дар floatва ҳатто дар double! Классро BigDecimalбарои оянда дар хотир доред, ба шумо ҳатман лозим мешавад :) Фу! Лекция хеле дароз буд, аммо шумо инро кардед: офарин! :) Дар дарси оянда вомехӯрем, барномасози оянда!
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION