JavaRush /Java блогу /Random-KY /Javaдагы BigDecimal

Javaдагы BigDecimal

Группада жарыяланган
Салам! Бүгүнкү лекцияда биз чоң сандар жөнүндө сүйлөшөбүз. Жок, чындап эле чоңдор жөнүндө. Буга чейин биз примитивдүү маалымат түрлөрү үчүн маани диапазондорунун tableсын бир нече жолу көргөнбүз. Ал мындай көрүнөт:
Примитивдик түрү Эс тутумдагы өлчөмү Маанилердин диапазону
byte 8 бит -128ден 127ге чейин
кыска 16 бит -32768ден 32767ге чейин
char 16 бит 0дөн 65536га чейин
int 32 бит -2147483648ден 2147483647ге чейин
узун 64 бит -9223372036854775808ден 9223372036854775807ге чейин
сүзүү 32 бит чейин (2-кубатка -149) чейин ((2-2 кубаттуулукка -23)*2 кубаттуулукка 127)
кош 64 бит чейин (-2 даражасына 63) чейин ((2 63 даражасына) - 1)
логикалык 8 (массивдерде колдонулганда), 32 (массив эместерде колдонулганда) чын же жалган
Эгерде биз бүтүн сандар жөнүндө сөз кыла турган болсок, эң сыйымдуулугу маалымат түрү long , ал эми калкыма чекиттер жөнүндө сөз болгондо double . Бирок, эгер бизге керектүү сан ушунчалык көп болсо, ал узакка да батпай калсачы ? Мүмкүн болгон Long маанилеринин диапазону абдан чоң, бирок дагы эле белгилүү бир өлчөм менен чектелген - 64 бит. Эгерде биздин абдан чоң саныбыздын салмагы 100 бит болсо, эмнени ойлоп таба алабыз? Бактыга жараша, эч нерсе ойлоп табуунун кереги жок. Javaда мындай учурлар үчүн эки атайын класс түзүлгөн - BigInteger (бүтүн сандар үчүн) жана BigDecimal (калкып жүрүүчү чекиттер үчүн). Алардын өзгөчөлүгү эмнеде? Биринчиден, алар теориялык жактан максималдуу өлчөмүнө ээ эмес. Теориялык жактан, анткени чексиз эс тутуму бар компьютерлер жок. Ал эми программада компьютердин эс тутумунун көлөмүнөн чоңураак сан түзсө, албетте программа иштебейт. Бирок мындай учурлар аз эмес. BigIntegerДемек, сандардын көлөмү иш жүзүндө чексиз деп айта алабыз BigDecimal. Бул класстар эмне үчүн колдонулат? Биринчиден, өтө жогорку тактык талаптары менен эсептөөлөр үчүн. Мисалы, адамдын өмүрү эсептөөлөрдүн тактыгынан көз каранды болгон программалар бар (самолёттор жана ракеталар үчүн программалык камсыздоо же медициналык жабдуулар үчүн). Ошондуктан, 150-ондук орун да маанилүү ролду ойносо, BigDecimalбул эң жакшы тандоо. Мындан тышкары, бул an objectилер көбүнчө каржы дүйнөсүндө колдонулат, мында эң кичине баалуулуктарга чейин эсептөөлөрдүн тактыгы да абдан маанилүү. Объекттер менен кантип иштөө керек BigIntegerжана BigDecimalалар жөнүндө эмнени эстен чыгарбоо керек? Бул класстардын an objectтери төмөнкүдөй түзүлөт:
public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
Параметр катары сапты өткөрүү мүмкүн болгон конструкторлордун бири гана. Here we use strings because our numbers exceed the maximum values long​​and double, and somehow we need to explain to the compiler exactly what number we want to get :) Just pass the number 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111 will not work: Java will try to “fit” берилген сан примитивдүү маалымат түрлөрүнүн бирине өткөн, бирок ал алардын бирине да туура келбейт. Ошондуктан, каалаган санды өткөрүү үчүн сапты колдонуу жакшы вариант. Эки класс тең өткөн саптардан автоматтык түрдө сандык маанилерди чыгара алат. Көп сандагы класстар менен иштөөдө эстен чыгарбоо керек болгон дагы бир маанилүү жагдай, алардын an objectтери өзгөрүлгүс ( Immutable) . Сиз класстын мисалынан өзгөрүлбөстүк принцибин жакшы билесиз Stringжана примитивдер үчүн (Integer, Long жана башкалар).
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
Консолдук чыгаруу:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Биздин сандар сиз күткөндөй өзгөргөн жок. Кошумча операция ийгorктүү болушу үчүн, сиз жаңы an object түзүп, ага кошуунун натыйжасын дайындашыңыз керек.
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
Консолдук чыгаруу:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Эми баары каалагандай иштеп жатат :) Баса, кошуу операциясы кандай адаттан тыш көрүнгөндүгүн байкадыңызбы?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
Бул дагы бир маанилүү жагдай. Көп сандагы класстар өз иштеринде +-*/ операторлорун колдонушпайт, тескерисинче, методдордун жыйындысын беришет. Келгиле, негизгилерин карап көрөлү (сиз, адаттагыдай эле, Oracle documentтеринен методдордун толук тизмесин таба аласыз: бул жерде жана бул жерде ).
  1. арифметикалык амалдарды аткаруу ыкмалары: add() , subtract(), multiply(), divide(). Кошуу, кемитүү, көбөйтүү жана бөлүү операциялары үчүн колдонулат.

  2. doubleValue(), intValue(), floatValue(), longValue()жана башкалар. - Көп санды Java примитивдүү түрүнө которуу үчүн колдонулат. Аларды колдонууда этият болуңуз жана кубаттуулуктагы айырманы унутпаңыз!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }

    Консолдук чыгаруу:

    
    8198552921648689607
  3. min()жана max()- өткөн эки чоң сандын минималдуу жана максималдуу маанисин табууга мүмкүндүк берет.
    Эскертүү: методдор статикалык эмес!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }

    Консолдук чыгаруу:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

BigDecimal тегеректөө башкаруусу

Бул тема өзүнчө бөлүмгө киргизилген, анткени чоң сандарды тегеректөө жана аны тууралоо анчалык деле жөнөкөй нерсе эмес. BigDecimalСиз сан үчүн ондук орундардын санын орното аласыз setScale(). Мисалы, биз 111.5555555555 санынын тактыгын үч ондук орунга коюуну каалайбыз. setScale()Бирок, биз 3 санын ыкмага аргумент катары өткөрүп , ошону менен маселебизди чече албайбыз . Жогоруда айтылгандай, BigDecimalбул жогорулатылган тактык менен эсептөө үчүн сандар. Азыркы түрүндө биздин санда 10 ондук орун бар. Биз алардын 7син жокко чыгарып, 3 гана калтыргыбыз келет. Ошондуктан, 3 санынан тышкары, тегеректөө режимин параметр катары өткөрүшүбүз керек . Бардыгы болуп 8 тегеректөө режими бар BigDecimal. Абдан көп! Бирок, эгер сиз программадагы эсептөөлөрдүн тактыгын чындап тууралашыңыз керек болсо, анда сизде бул үчүн керектүү нерселердин баары болот. Ошентип, бул жерде 8 тегеректөө режими бар BigDecimal:
  1. ROUND_CEILING- тегеректөө

    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
  2. ROUND_DOWN- разрядды жок кылуу

    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
  3. ROUND_FLOOR- тегеректөө

    111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555

  4. ROUND_HALF_UP— тегеректөө, эгерде ондук чекиттен кийинки сан >= .5

    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
  5. ROUND_HALF_DOWN— ондук чекиттен кийинки сан > .5 болсо тегеректөө

    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
  6. ROUND_HALF_EVEN— тегеректөө ондук чекиттин сол жагындагы санга жараша болот. Эгерде сол жактагы сан жуп болсо, анда тегеректөө ылдый карай жүргүзүлөт. Эгерде ондук чекиттин сол жагындагы сан так болсо, ал тегеректелген болот.

    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2

    Ондук чекиттин сол жагындагы сан - 2 - жуп. Tagеректөө ылдый пайда болот. Биз 0 ондук белгини талап кылгандыктан, натыйжа 2 болот.

    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4

    Ондук чекиттин сол жагындагы сан - 3 - так. Tagеректөө жогору карай жүрөт. Биз 0 ондук белгини талап кылгандыктан, натыйжа 4 болот.

  7. ROUND_UNNECCESSARY— тегеректөө режимин кандайдыр бир ыкмага өткөрүү керек болгон учурларда колдонулат, бирок санды тегеректөө керек эмес. ROUND_UNNECCESSARY режими коюлганда, сиз санды тегеректоого аракет кылсаңыз, ArithmeticException ыргытылат.

    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
  8. ROUND_UP- тегеректөө.

    111.5551 -> setScale(3, ROUND_UP) -> 111.556

Чоң сандарды салыштыруу

Бул суроо да маанилүү. Сиз буга чейин эле бул ыкма Java an objectилерин салыштыруу үчүн колдонулганын эстейсиз equals(). Ал же тилдин өзү тарабынан камсыздалат (Javaда орнотулган класстарда) же программист тарабынан жокко чыгарылат. Бирок класстык an objectилерде салыштыруу BigDecimalыкмасын колдонуу сунушталbyte. equals()Мунун себеби, BigDecimal.equals()эки сандык ыкма эки сан бирдей мааниге жана масштабга ээ болгондо гана чындыкты кайтарат: Келгиле, y жана y ыкмаларынын жүрүм-турумун салыштырып көрөлү : equals()DoubleBigDecimal
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));

   }
}
Консолдук чыгаруу:

true
false
Көрүнүп тургандай, с шартында 1,5 жана 1,50 сандары BigDecimalбирдей эмес болуп чыкты! equals()Бул класстагы методдун өзгөчөлүгүнөн улам болду BigDecimal. Экөөнү туурараак салыштыруу үчүн, BigDecimalбул ыкманы колдонуу жакшы compareTo():
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
Консолдук чыгаруу:

0
Метод compareTo()0 кайтарды, бул 1,5 жана 1,50 дегенди билдирет. Бул биз күткөн натыйжа! :) Ушуну менен бүгүнкү сабагыбыз жыйынтыкталды. Милдеттерге кайтып келүүгө убакыт келди! :)
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION