JavaRush /وبلاگ جاوا /Random-FA /BigDecimal در جاوا

BigDecimal در جاوا

در گروه منتشر شد
سلام! در سخنرانی امروز ما در مورد اعداد بزرگ صحبت خواهیم کرد. نه، در مورد آنهایی که واقعاً بزرگ هستند. قبلاً ، بیش از یک بار جدولی از محدوده‌های مقادیر برای انواع داده‌های اولیه دیده‌ایم. به نظر می رسد این است:
نوع اولیه اندازه در حافظه محدوده ارزش ها
بایت 8 بیت -128 تا 127
کوتاه 16 بیت به -32768 تا 32767
کاراکتر 16 بیت از 0 تا 65536
بین المللی 32 بیت از -2147483648 تا 2147483647
طولانی 64 بیت از -9223372036854775808 تا 9223372036854775807
شناور 32 بیت از (2 به توان -149) تا ((2-2 به توان -23)*2 به توان 127)
دو برابر 64 بیت از (2- به توان 63) تا ((2 به توان 63) - 1)
بولی 8 (هنگامی که در آرایه ها استفاده می شود)، 32 (در صورت استفاده در غیر آرایه ها) درست یا غلط
اگر در مورد اعداد صحیح صحبت می کنیم، بزرگ ترین نوع داده طولانی است و وقتی در مورد اعداد ممیز شناور صحبت می کنیم، دو برابر می شود . اما اگر تعداد مورد نیاز ما آنقدر زیاد باشد که حتی به اندازه طولانی هم نباشد چه؟ محدوده مقادیر احتمالی Long بسیار بزرگ است، اما هنوز به اندازه خاصی محدود است - 64 بیت. اگر عدد بسیار بزرگ ما 100 بیت وزن داشته باشد، چه چیزی می توانیم به دست آوریم؟ خوشبختانه شما نیازی به اختراع چیزی ندارید. در جاوا، دو کلاس ویژه برای چنین مواردی ایجاد شد - BigInteger (برای اعداد صحیح) و BigDecimal (برای اعداد ممیز شناور). ویژگی آنها چیست؟ اول از همه، آنها از نظر تئوری حداکثر اندازه ندارند. از نظر تئوری، زیرا هیچ کامپیوتری با حافظه بی نهایت وجود ندارد. و اگر عددی در برنامه ایجاد کنید که از حجم حافظه کامپیوتر بزرگتر باشد، مسلماً برنامه کار نخواهد کرد. اما چنین مواردی بعید است. بنابراین می توان گفت که اندازه اعداد عملا نامحدود BigIntegerاست . BigDecimalاین کلاس ها برای چه مواردی استفاده می شوند؟ اول از همه، برای محاسبات با دقت بسیار بالا. به عنوان مثال، برنامه هایی وجود دارد که در آنها زندگی انسان می تواند به دقت محاسبات بستگی داشته باشد (نرم افزاری برای هواپیماها و موشک ها یا تجهیزات پزشکی). بنابراین، اگر حتی 150 رقم اعشار نقش مهمی ایفا کند، BigDecimalبهترین انتخاب است. علاوه بر این، اغلب از این اشیاء در دنیای مالی استفاده می شود، جایی که دقت محاسبات تا کوچکترین مقادیر نیز بسیار مهم است. چگونه با اشیاء کار کنیم BigIntegerو BigDecimalچه چیزی در مورد آنها مهم است؟ آبجکت های این کلاس ها به صورت زیر ایجاد می شوند:
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 valueslong​​​ double​and , and somehow we need to explain to the compiler exactly what number we want to get :) Just pass the number 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 111111 to the constructor 1111111111111111111111111111111111111111111111111111111111111 111111 will not work: Java will عدد ارسال شده را در یکی از انواع داده های ابتدایی "تناسب" کنید، اما در هیچ یک از آنها قرار نمی گیرد. بنابراین استفاده از رشته برای عبور عدد مورد نظر گزینه خوبی است. هر دو کلاس می توانند به طور خودکار مقادیر عددی را از رشته های ارسال شده استخراج کنند. نکته مهم دیگری که باید هنگام کار با کلاس های اعداد بزرگ به خاطر بسپارید این است که اشیاء آنها تغییرناپذیر هستند ( Immutable) . شما قبلاً به خوبی با اصل تغییرناپذیری از طریق مثال یک کلاس Stringو کلاس های wrapper برای موارد اولیه (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
اعداد ما همانطور که انتظار دارید تغییر نکرده است. برای موفقیت عملیات جمع، باید یک شی جدید ایجاد کنید و نتیجه جمع را به آن اختصاص دهید.
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 پیدا کنید: اینجا و اینجا ).
  1. روش های انجام عملیات حسابی: add() , subtract(), multiply(), divide(). به ترتیب برای عملیات جمع، تفریق، ضرب و تقسیم استفاده می شود.

  2. doubleValue()، intValue()، floatValue()، و longValue()غیره. - برای تبدیل یک عدد بزرگ به نوع اولیه جاوا استفاده می شود. هنگام استفاده از آنها مراقب باشید و تفاوت ظرفیت را به خاطر بسپارید!

    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 را روی سه رقم اعشار قرار دهیم. با این حال، ما نمی توانیم عدد 3 را به عنوان آرگومان به روش منتقل کنیم setScale()و در نتیجه مشکل خود را حل کنیم. همانطور که در بالا ذکر شد، 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- اگر عدد بعد از اعشار >= 0.5 باشد، گرد کردن

    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
  5. ROUND_HALF_DOWN- اگر عدد بعد از نقطه اعشار > 0.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 - زوج است. گرد کردن به پایین رخ می دهد. از آنجایی که ما به 0 رقم اعشار نیاز داریم، نتیجه 2 خواهد بود.

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

    عدد سمت چپ نقطه اعشار - 3 - فرد است. گرد شدن به سمت بالا رخ می دهد. از آنجایی که ما به 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

مقایسه اعداد بزرگ

این سوال نیز مهم است. قبلاً به یاد دارید که این روش برای مقایسه اشیاء در جاوا استفاده می شود equals(). این یا توسط خود زبان ارائه می شود (در مورد کلاس های داخلی جاوا) یا توسط برنامه نویس لغو می شود. اما در مورد اشیاء کلاس، BigDecimalاستفاده از روش equals()برای مقایسه توصیه نمی شود. دلیل این امر این است که BigDecimal.equals()روش دو عددی فقط زمانی true را برمی گرداند که دو عدد دارای مقدار و مقیاس یکسان باشند : بیایید رفتار متدهای equals()y Doubleو y را با هم مقایسه کنیم BigDecimal:
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 در مورد c 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