CodeGym /وبلاگ جاوا /Random-FA /BigDecimal در جاوا
John Squirrels
مرحله
San Francisco

BigDecimal در جاوا

در گروه منتشر شد
سلام! در درس امروز، در مورد اعداد بزرگ صحبت خواهیم کرد. نه، منظورم واقعا بزرگ است. ما قبلا بارها و بارها با جدول محدوده مقادیر برای انواع داده های اولیه مواجه شده ایم. به نظر می رسد این است:
نوع اولیه اندازه در حافظه محدوده ارزش
بایت 8 بیت -128 تا 127
کوتاه 16 بیت -32768 تا 32767
کاراکتر 16 بیت 0 تا 65536
بین المللی 32 بیت -2147483648 تا 2147483647
طولانی 64 بیت -9223372036854775808 تا 9223372036854775807
شناور 32 بیت (2 به توان 149-) تا ((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);
   }
}
ارسال یک رشته به سازنده تنها یکی از گزینه های ممکن است. در اینجا ما از رشته ها استفاده می کنیم، زیرا اعداد ما از حداکثر مقادیر برای طولانی و دو برابر بیشتر می شوند، و ما به روشی نیاز داریم تا به کامپایلر توضیح دهیم که کدام عدد را می خواهیم ایجاد کنیم :) 1111111111111111111111111111111111111111111111111111111111111111111111111111 به سازنده کار نمی کند: جاوا سعی خواهد کرد عدد ارسال شده را در یکی از انواع داده های اولیه جمع کند، اما در هیچ یک از آنها قرار نمی گیرد. به همین دلیل استفاده از رشته برای عبور عدد مورد نظر گزینه خوبی است. هر دو کلاس می توانند به طور خودکار مقادیر عددی را از رشته های ارسال شده استخراج کنند. نکته مهم دیگری که باید هنگام کار با کلاس های بزرگ به خاطر بسپارید این است که اشیاء آنها غیرقابل تغییر هستند ( 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);

   }
}
خروجی کنسول:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 
همانطور که انتظار دارید، تعداد ما تغییر نکرده است. برای انجام عملیات جمع، باید یک شی جدید ایجاد کنید تا نتیجه عملیات را دریافت کنید.

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);

   }
}
خروجی کنسول:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
ببینید، اکنون همه چیز همانطور که باید کار می کند :) به هر حال، آیا متوجه شدید که عملیات اضافه چقدر غیرعادی به نظر می رسد؟

BigInteger result = integer.add(BigInteger.valueOf(33333333));
این نکته مهم دیگری است. کلاس های اعداد بزرگ از عملگرهای + - * / استفاده نمی کنند. در عوض، آنها مجموعه ای از روش ها را ارائه می دهند. بیایید با اصلی ترین آنها آشنا شویم (مثل همیشه، می توانید لیست کاملی از روش ها را در اسناد اوراکل پیدا کنید: اینجا و اینجا ).
  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

این مبحث بخش جداگانه خود را دارد، زیرا گرد کردن اعداد بزرگ و پیکربندی رفتار گرد کردن چندان ساده نیست. می‌توانید از متد setScale() برای تنظیم تعداد ارقام اعشار برای BigDecimal استفاده کنید . به عنوان مثال، فرض کنید می خواهیم عدد 111.5555555555 دارای سه رقم بعد از اعشار باشد. با این حال، با ارسال عدد 3 به عنوان آرگومان به متد setScale() نمی‌توانیم به آنچه می‌خواهیم برسیم . همانطور که در بالا ذکر شد، BigDecimal برای نمایش اعداد با الزامات دقیق در مورد دقت محاسباتی است. در شکل فعلی، عدد ما 10 رقم بعد از نقطه اعشار دارد. ما می خواهیم 7 تا از آنها را رها کنیم و فقط 3 مورد را نگه داریم. بر این اساس علاوه بر عدد 3 باید از حالت گرد کردن نیز عبور کنیم. BigDecimal در مجموع دارای 8 حالت گرد است. آن خیلی زیاد است! اما اگر واقعاً نیاز دارید که دقت محاسبات خود را تنظیم کنید، هر آنچه را که نیاز دارید خواهید داشت. بنابراین، در اینجا 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

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

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