JavaRush /בלוג Java /Random-HE /BigInteger ו-BigDecimal

BigInteger ו-BigDecimal

פורסם בקבוצה
ב-Java, אפליקציה מורכבת ממחלקות, ומחלקות מורכבות משיטות ומשתנים. משתנים, בתורם, מחולקים לפרימיטיבי ולהתייחסות. BigInteger ו- BigDecimal - 1ישנם 8 סוגים של משתנים ב-Java, ולמעט booleanו- char, הם מחולקים לסוגים הבאים:
  • מספרים שלמים: byte, short, intו long;
  • נקודה צפה (נקראת גם מספרים ממשיים): floatו double.
בתוך הקבוצות הקטנות הללו, הבדלים קיימים רק בטווח הערכים שניתן להכיל (ולפיכך, השטח התפוס של משתנה כזה משתנה). הגדול ביותר מבין סוגי המספרים השלמים הוא long, עם טווח מ-9223372036854775808 עד 9223372036854775807. מבין מספרי הנקודה הצפה, , doubleעם טווח של 1.7e-308 עד 1.7e+308. אתה יכול לקרוא עוד על מספרים אמיתיים במאמר זה . אבל מה אם נצטרך לאחסן מספרים גדולים מהטווח המקובל? במקרה זה, נצטרך BigIntegerו BigDecimal.

BigInteger ב-Java

מחלקת Java BigIntegerמשמשת כאנלוגי לערכי מספרים שלמים באורך שרירותי שאין להם מגבלת 64 סיביות של ארוך. יתר על כן, הוא צאצא של המחלקה Number, כמו עטיפות סטנדרטיות לסוגים מספריים פשוטים - Integer, Long, Byte, Doubleוכן הלאה - ולכן יש לה יישומים של שיטות המובילות לסוגים פשוטים:
BigInteger value = new BigInteger("32145");

int intValue = value.intValue();//32145

long longValue = value.longValue();//32145

double doubleValue = value.doubleValue();//32145.0
מיד אנו רואים יצירה של אובייקט כזה BigIntegerכשהערך שלנו מועבר לבנאי, אבל בפורמט מחרוזת. ראוי לציין שיש לו יותר ממעצב אחד, אבל לכל אירוע. אם טיפוסים פרימיטיביים אינם יכולים להכיל את מלוא כמות הנתונים מ- BigInteger, הנתונים יקוצצו לטווח של אותו סוג פרימיטיבי. אך יחד עם זאת, ישנם אנלוגים לשיטות אלו ( intValueExact()וכו longValueExact()'), כאשר ההבדל היחיד הוא שאם הסוג הפשוט שאליו מתבצעת ההמרה אינו מתאים לטווח הנתונים, נזרק ArithmeticException .

קבועים של מספר שלם

לשימוש פנימי, למחלקה יש קבועים:
BigInteger.ZERO
BigInteger.ONE
BigInteger.TEN
אלה הם אובייקטים קבועים BigIntegerעם ערכים, בהתאמה 0, 1ו 10.

שיטות BigInteger

אחת התכונות העיקריות של מחלקה זו היא שהיא מלאה בשיטות המיישמות פעולות אריתמטיות סטנדרטיות בג'אווה. לדוגמה:
  • פעולות סיכום:

    BigInteger firstValue = new BigInteger("37995");
    BigInteger secondValue = new BigInteger("35466");
    BigInteger resultValue =  firstValue.add(secondValue);//73461
  • פעולות כפל:

    BigInteger firstValue = new BigInteger("37995");
    BigInteger secondValue = new BigInteger("35466");
    BigInteger resultValue =  firstValue.multiply(secondValue);//1347530670
  • פעולות של מציאת השארית כאשר מחלקים מספר אחד במספר אחר:

    BigInteger firstValue = new BigInteger("37995");
    BigInteger secondValue = new BigInteger("35466");
    BigInteger resultValue =  firstValue.remainder(secondValue);//2529
  • קבלת הערך המוחלט של מספר (כלומר, modulo, unsigned):

    BigInteger firstValue = new BigInteger("-37995");
    BigInteger resultValue =  firstValue.abs();//37995
ישנן גם שיטות לפעולות מורכבות יותר (ספציפיות):
  • פעולות עם חישוב מוד :

    BigInteger firstValue = new BigInteger("-34");
    BigInteger secondValue = new BigInteger("5");
    BigInteger resultValue = firstValue.mod(secondValue); //1
ישנן מספר וריאציות שונות של פונקציה זו:
  • השגת מספר אקראי וציון מספר הסיביות שהערך המתקבל ישתמש בהן:

    BigInteger firstValue = BigInteger.probablePrime(8, new Random());//211
    BigInteger secondValue = BigInteger.probablePrime(16, new Random());//42571
  • פעולות העברה בכיוון סיביות (זה >> n)

    העבר שמאלה:

    BigInteger firstValue = new BigInteger("5");
    BigInteger firstResultValue = firstValue.shiftLeft(3);//40

    העבר ימינה:

    BigInteger secondValue = new BigInteger("34");
    BigInteger secondResultValue = secondValue.shiftRight(2); //8
כמובן שעדיף להסתכל על רשימת השיטות המלאה בתיעוד . BigInteger ו-BigDecimal - 2

BigDecimal ב-Java

כאשר אנו זקוקים למספר ממשי באורך שרירותי, נעשה שימוש במחלקת Java - BigDecimal. ככלל, הוא משמש לעבודה עם כספים במקום double, מכיוון שהוא נותן יותר אפשרויות התאמה אישית. Like ו BigInteger, BigDecimalהוא צאצא של מחלקה Numberויש לו שיטות המחזירות את הערך של אובייקט כסוג פרימיטיבי ספציפי:
BigDecimal value = new BigDecimal(35563.3);

long longValue = value.longValue();//35563

double doubleValue = value.doubleValue();//35563.3
כפי שאנו יכולים לראות כאשר מצמצמים ל- long, נשאר רק החלק השלם, והמקומות העשרוניים נמחקים.

בנאים BigDecimal

נסתכל מקרוב על הבנאים BigDecimal, מכיוון שלכיתה יש מבחר רחב הרבה יותר מהם. יש בנאים שמאפשרים להגדיר את הערך של אובייקט בדרכים שונות (באמצעות העברת , , ואפילו int) long, doubleויש כאלה שמאפשרים זאת. הגדר את ההגדרות של האובייקט שנוצר (שיטות עיגול, מספר מקומות עשרוניים): StringBigInteger
BigDecimal firstValue = new BigDecimal("455656.545");//455656.545
הכל ברור כאן, אנו מגדירים ישירות את הערך ומספר המקומות העשרוניים שאנו רוצים לראות.
BigDecimal secondValue = new BigDecimal(3445.54);//3445.5399999999999636202119290828704833984375
התוצאות של בנאי זה יכולות להיות די בלתי צפויות, מכיוון שאנו מציינים כפול, שמטבעו הוא סוג מאוד מעורפל. לכן, בדרך כלל מומלץ להשתמש בקונסטרוקטור String.
BigDecimal thirdValue = new BigDecimal(3445.554645675444, MathContext.DECIMAL32);//3445.555
קבענו double, אבל במקביל גם קבענו פרמטר שמתאר את כלל העיגול (המכיל את מספר המקומות העשרוניים ואת האלגוריתם לעיגול).
char[] arr = new String("455656.545").toCharArray();

BigDecimal fourthValue = new BigDecimal(arr, 2, 6);//5656.5
אנחנו מגדירים מערך של תווים מאיזה אלמנט אנחנו לוקחים את הערכים של האובייקט וכמה מהאלמנטים האלה אנחנו לוקחים.
BigDecimal fifthValue = new BigDecimal(new BigInteger("44554"), 3);//44.554
אנחנו לוקחים אובייקט קיים כבר BigInteger, מגדירים את מספר המקומות העשרוניים.

שיטות BigDecimal

המחלקה BigDecimalמכילה גם שיטות לפעולות אריתמטיות שונות, אך BigIntegerאין לה שיטות לעבודה עם ביטים, כמו . אך עם זאת, המאפיין העיקרי BigDecimalהוא הגמישות בעבודה עם מספרי נקודה צפה. בואו נסתכל על כמה טכניקות שנותנות לנו את הכוח לשלוט במספרים האמיתיים:
  • נקבל את הדיוק (מספר המספרים):

    BigDecimal value = new BigDecimal("454334.34334");
    int result = value.precision();//11
  • הגדר את מספר המקומות העשרוניים ואת כלל העיגול:

    BigDecimal firstValue = new BigDecimal(3445.544445);
    
    BigDecimal secondValue = firstValue.setScale(3,BigDecimal.ROUND_CEILING);//3445.545

    להלן נסקור מקרוב את הקבועים לקביעת כללי עיגול.

  • חלק BigDecimalבאחר BigDecimal, תוך ציון המספר הנדרש של מקומות עשרוניים וכלל העיגול:

    BigDecimal firstValue = new BigDecimal("455656.545");
    
    BigDecimal secondValue = new BigDecimal(3445.544445);
    
    BigDecimal result = firstValue.divide(secondValue, 2,RoundingMode.DOWN);//132.24
  • הזזת נקודה עשרונית ימינה/שמאלה במספר מסוים של מקומות:

    BigDecimal value = new BigDecimal("455656.545");
    BigDecimal firstResult = value.movePointRight (2);//45565654.5
    BigDecimal secondResult = value.movePointLeft (2);//4556.56545
  • חתוך את האפסים הבאים:

    BigDecimal value = new BigDecimal("45056.5000");
    BigDecimal result = value.stripTrailingZeros();//45056.5

    אם יש לנו את כל האפסים בחלק האמיתי ויש גם אפסים בכל החלק (או שאין לנו מקומות עשרוניים בכלל), אז:

    BigDecimal value = new BigDecimal("450000.000");
    BigDecimal result = value.stripTrailingZeros();//4.5E+5

כללי עיגול BigDecimal

כדי לקבוע כללי עיגול, בפנים BigDecimalנוכל לראות קבועים מיוחדים המתארים אלגוריתמי עיגול: ROUND_UP- עיגול מאפס, עיגול לכיוון החלק האמיתי:
BigDecimal firstValue = new BigDecimal("2.578");
BigDecimal firstResult =  firstValue.setScale(1, BigDecimal.ROUND_UP );//2.6
BigDecimal secondValue = new BigDecimal("-2.578");
BigDecimal secondResult = secondValue.setScale(1, BigDecimal.ROUND_UP );//-2.5
ROUND_DOWN- עיגול לאפס, כלומר, חיתוך של החלק האמיתי:
BigDecimal firstValue = new BigDecimal("2.578");
BigDecimal firstResult =  firstValue.setScale(1, BigDecimal.ROUND_DOWN  );//2.5
BigDecimal secondValue = new BigDecimal("-2.578");
BigDecimal secondResult = secondValue.setScale(1, BigDecimal.ROUND_DOWN  );//-2.6
ROUND_CEILING- עיגול לאינסוף חיובי. כלומר, אם המספר שלנו חיובי, אז -> ROUND_UP, אם שלילי, אז ->ROUND_DOWN
BigDecimal firstValue = new BigDecimal("2.578");
BigDecimal firstResult =  firstValue.setScale(1, BigDecimal.ROUND_CEILING);//2.6
BigDecimal secondValue = new BigDecimal("-2.578");
BigDecimal secondResult = secondValue.setScale(1, BigDecimal.ROUND_CEILING);//-2.5
ROUND_FLOOR- עיגול לאינסוף שלילי, כלומר, אם המספר שלנו חיובי, אז -> ROUND_DOWN, אם שלילי, אז ->ROUND_UP
BigDecimal firstValue = new BigDecimal("2.578");
BigDecimal firstResult =  firstValue.setScale(1, BigDecimal.ROUND_FLOOR);//2.5
BigDecimal secondValue = new BigDecimal("-2.578");
BigDecimal secondResult = secondValue.setScale(1, BigDecimal.ROUND_FLOOR);//-2.6
עבור הערך הנדון, נשקול את המספר הקרוב ביותר הזה עם מקום עשרוני קצוץ כשכן הקרוב ביותר של המספר הנבדק. לדוגמה, 2.43 יהיה קרוב יותר ל-2.4 מ-2.5, אך 2.48 יהיה קרוב יותר ל-2.5. ROUND_HALF_DOWN- עיגול ל"שכן הקרוב". אם שני השכנים נמצאים במרחק שווה מערך מסוים, אז מתבצע עיגול לאפס. מרחק שווה הוא, למשל, כאשר המספר שמתעגל הוא 5, והוא באותו מרחק מ-0 ו-10):
BigDecimal firstValue = new BigDecimal("2.58");
BigDecimal firstResult =  firstValue.setScale(1, BigDecimal.ROUND_HALF_DOWN );//2.6
BigDecimal secondValue = new BigDecimal("2.55");
BigDecimal secondResult = secondValue.setScale(1, BigDecimal.ROUND_HALF_DOWN );//2.5
ROUND_HALF_UP- מצב עיגול לכיוון "השכן הקרוב". אם שני השכנים נמצאים במרחק שווה, מבצעים עיגול כלפי מעלה (זהו אותו עיגול שלימדו אותנו בבית הספר):
BigDecimal firstValue = new BigDecimal("2.53");
BigDecimal firstResult =  firstValue.setScale(1, BigDecimal.ROUND_HALF_UP  );//2.5
BigDecimal secondValue = new BigDecimal("2.55");
BigDecimal secondResult = secondValue.setScale(1, BigDecimal.ROUND_HALF_UP  );//2.6
ROUND_HALF_EVEN- עיגול ל"שכן הקרוב" אם שני השכנים אינם במרחק שווה. במקרה זה, אם לפני המספר שמתעגל יש מספר אי זוגי, הוא מעוגל כלפי מעלה, ואם הוא זוגי, הוא מעוגל כלפי מטה:
BigDecimal firstValue = new BigDecimal("2222.2225");
BigDecimal secondValue = firstValue.setScale(3,BigDecimal.ROUND_HALF_EVEN );//2222.222
אנו מקבלים את התוצאה הזו מכיוון שבעת עיגול, 5 מסתכל על המספר הקודם 2, ורואים שהוא זוגי, מתעגל כלפי מטה. אבל אם:
BigDecimal firstValue = new BigDecimal("2222.22255");
BigDecimal secondValue = firstValue.setScale(3,BigDecimal.ROUND_HALF_EVEN );//2222.223
העיגול הזה עולה למעלה, מכיוון שה-5 האחרון מסתכל על הערך הקודם ורואה מספר אי-זוגי. כתוצאה מכך, המספר מעוגל כלפי מעלה ל-6, ולאחר מכן גם ה-6 הבאים מעוגלים. אבל השישה כבר לא מסתכלת על המספר משמאל, מכיוון שהמספר בבירור קרוב יותר כלפי מעלה, וכתוצאה מכך ה-2 האחרון גדל ב-1. ROUND_UNNECESSARY- משמש כדי לבדוק שאין צורך לעגל את המספר. כלומר, אנו בודקים שלמספר יש את המספר הנדרש של מקומות עשרוניים:
BigDecimal firstValue = new BigDecimal("2.55");
BigDecimal firstResult =  firstValue.setScale(2, BigDecimal.ROUND_UNNECESSARY);//2.55
הכל בסדר כאן, לערך יש שתי ספרות ואנחנו בודקים שיש רק שתי ספרות אחרי הנקודה העשרונית. אבל אם:
BigDecimal secondValue = new BigDecimal("2.55");
BigDecimal secondResult = secondValue.setScale(1, BigDecimal.ROUND_UNNECESSARY);
אז נקבל - ArithmeticException, מכיוון שהערך הנבדק חורג ממספר המקומות העשרוניים שצוין. אבל אם נבדוק שני מקומות עשרוניים, אבל למעשה יש שם אחד, אז החריג לא ייזרק, והספרות החסרות פשוט מתווספות באפסים:
BigDecimal thirdValue = new BigDecimal("2.5");
BigDecimal thirdResult = thirdValue.setScale(3, BigDecimal.ROUND_UNNECESSARY   );//2.500
אני רוצה גם לציין של-y BigDecimalיש קבועים הדומים לקבועים BigInteger ZERO, ONEו TEN. הנה קישור לתיעוד . ולבסוף: כפי שבטח שמתם לב, כשמבצעים פעולות עם אובייקטים BigIntegerו- BigDecimal, אנחנו לא משנים את הישנים, אלא תמיד מקבלים חדשים. זה אומר לנו שהם immutable, כלומר, בלתי ניתנים לשינוי לאחר יצירתם, בדיוק כמו String. במילים אחרות, כל השיטות שלהם לא יכולות לשנות את המצב הפנימי של האובייקט; לכל היותר, הן יכולות להחזיר אובייקט חדש עם הפרמטרים שצוינו על ידי הפונקציה שבה אנו משתמשים.
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION