نمايش دادن مقادير ارزی با BigDecimal
این مقاله به بررسی نحوه نمایش و کنترل مقادیر ارزی با استفاده از کلاس BigDecimal در جاوا میپردازد. BigDecimal یک کلاس در جاوا است که یک روش برای ذخیره و کنترل اعداد اعشاری با دقت خیلی بالا فراهم میکند. این کلاس محدودیتهایی دارد، از جمله نمیتوان برای اعمال ریاضی اصلی ± و تقسیم، از علائم گفته شده استفاده کرد و باید از متدهای مربوطه مانند add و multiply استفاده کرد. این کلاس برای رفع مشکل دقت و درستی ذخیرهسازی مقادیر طراحی شده است.
Table of contents
زبان جاوا در مقابله با داده های بزرگ
همانطور که در ویدئوی آموزشی انواع دادهها در دوره ملزومات جاوا حال حاضر گفته شد، انواع عددی دارای محدودیتهایی هستند. شاید حالتی پیش بیاید که مجبور شویم با دادههای بسیار بزرگ کار کنیم به طوری که انواع دادههای موجود پاسخگو نیاز ما نباشند. اگر اندازههای دادهها به قدری باشد که مثلاً نوع داده int نتواند داده ما را ذخیره کند و حتی نوع داده long نیز نتواند این کار را بکند، باید فکر دیگری به حال ذخیره و کار با دادهها کرد. زبان جاوا برای حل این مشکل دو کلاس معرفی کرده که بتوانیم انواع داده بزرگ را در آنها ذخیره کنیم. یکی برای دادههای صحیح با نام BigInteger و دیگری برای ذخیره دادههای اعشاری با نام BigDecimal.
که در این بخش از آموزش میخواهم نحوه کار و کاربرد این کلاسها را توضیح دهم.
محاسبات داده از نوع double در جاوا
نوع دادههای اولیه عددی بطور باورنکردنیای برای ذخیره مقادیرِ منفرد در حافظه بسیار مفید فایده هستند. البته به طورِ خاص نوع دادههای double و float خیلی دقیق نیستند. این بخاطر این است که این مقادیر از روشی در حافظه ذخیره میشوند که دقیقاً با مقدارِ واقعی مطابقت نمیکند. مثلًا، یک متغیرِ دابل 64 بیت از حافظه را اشغال میکند ولی جاوا از همه آن 64 بیت استفاده نمیکند، و فقط قسمت مهمِ یک عدد را ذخیره میکند و این باعث میشود که موقعِ جمع کردن مقادیر با هم و گرفتن خروجی مقادیر عجیب غریبی ببینید.
در این پروژه جاری که اسم آن Currency است، من کلاس main را از قبل باز کردم و این کلاس یک اعلان از double با یک مقدار 0.012 دارد.
حالا میخواهم یک متغیر دیگر هم از نوع دابل با نام pSum ایجاد و اعلان کنم، که این pSum مخفف primitive sum به معنی جمع متغیرهای از نوع داده اولیه است.
و این مقدار را با سه بار جمع کردن value با خودش محاسبه میکنم و بدست میاورم یعنی value + value + value.
خب؛ مقدار value که هست 0.012 و مشخص است که جواب عبارت 0.012 + 0.012 + 0.012 باید 0.036 بشود.
خب؛ حالا خروجی میگیرم.
من یکبار دیگر از s out استفاده میکنم و آنرا به System.out.println گسترش میدهم و داخل پرانتز برچسب “Sum of primitives: ” را وارد میکنم و بعد متغیر pSum را به آن اضافه میکنم و از کد اجرا میگیرم.
و این نتیجهای است که به من میدهد Sum of primitives: 0.036 و بعد هم یک عالمه صفر و در آخر هم یک عدد 4.
واضحِ است که مقداری که در حافظه ذخیره شده دقیقاً آنچیزی که انتظار داشتیم نیست و اگر بیاییم این مقدار را باز هم با خودش جمع کنیم، نتیجه حاصل میتواند بیشتر و بیشتر مبهم شود.
اگر من این مقدار را در یک database یا پایگاه داده ذخیره کنم و یکسری محاسبات دیگر روی آن انجام بدهم، باز هم همه این مشکلات میتوانند به وجود بیایند.
کلاس BigDecimal در جاوا
برای حل این مشکل، جاوا آمده کلاسی با نامِ BigDecimal را در اختیار ما قرار داده است. در واقع از این نوع کلاس دو مدل وجود دارد. یکی با نامِ BigInteger و یکی با نامِ BigDecimal، البته BigDecimal به طور خاص برای رفع این مشکل دقت و درستی ذخیره سازی مقادیر طراحی شده.
البته این هم بگویم که این کلاس محدودیتهایی دارد. یکی از محدودیتهای این کلاس این است که نمیشود برای اعمال ریاضی اصلی +- و تقسیم، از علائم گفته شده استفاده کرد و باید از متدهای مربوطه مانند add و multiply استفاده کرد. نحوه پیاده سازی این کلاسها به این شکل است که برای ذخیره اعداد بزرگ از یک آرایه استفاده میشود که در هر خانه یک عدد قرار میگیرد و سقف ذخیرهسازی این کلاسها بزرگترین مقدار نوع داده int خواهد بود که مقدار بزرگی است. نکتهای که باید به آن اشاره کرد این است که برخلاف زبان قدرتمند سی پلاس پلاس که میشود در آن عملگرهایی مانند + و – را overload کرد در جاوا این امکان وجود ندارد و مجبوریم که برای کلاسهایی مانند BigInteger از متدهای مربوطه استفاده کنیم.
برای استفاده از BigDecimal در اعداد، اول از همه باید آن عدد را به یک رشته تبدیل کنید.
من یک متغیر از نوع string اعلان و ایجاد میکنم و نام آنرا میگذارم strValue و بعد از کلاس دابل استفاده میکنم، که کلاس کمکی نوع داده دابل است و متد toSting را برای آن فراخونی میکنم و متغیر value را به آن میدهم.
بعد مقدار strValue را در خروجی نشان میدهم، با یک برچسب strValue و بعد هم اضافه کردن متغیر strValue.
خب؛ میبینیم که خروجی به شکل درستی نمایش داده میشود.
حالا، من این رشته را میگیرم و آنرا به یک نمونه از کلاس BigDecimal میدهم.
خب؛ حالا باید یک BigDecimal را اعلان کنیم، پس ابتدا نام این کلاس را تایپ میکنم و بعد با فشردن اینتر کلاس مورد نظر من از لیست پیشنهادی انتخاب میشود.
توجه داشته باشید، در بالا کد، یک عبارت ایمپورت جدید اضافه شد.
من بعداً این ایمپورتها را بطور کامل برای شما توضیح میدهم؛ ولی چیزی که اینجا مهم است بدانید این است که کلاسهایی که تا حالا من استفاده کردم، مثل String، Double و غیره؛ اعضاء پکیجی به نام Java.lang هستند.
این پکیج همیشه برای کدنویسی در دسترسِ شما است. ولی وقتی نیاز داشته باشید که از کلاسهایی که عضو سایرِ پکیجها هستند استفاده کنید، مثل Java.math، باید به صورت صریح آن پکیجها را به کدتان ایمپورت و اضافه کنید.
خب؛ برویم سراغ اعلان متغیر از نوع کلاس BigDecimal که نام آنرا میگذارم bigValue.
و حالا باید با استفاده از کلمه کلیدی new و بعد نام کلاس بطور مجدد یک نمونه از این شیء ایجاد بشود و بعد رشته strValue را به عنوان آرگومان ورودی به آن میدهم.
پس من آمدم این عدد را به صورت یک شیء پیچیده درآوردم و حالا میخواهم دوباره یک متغیر sum ایجاد کنم.
یکبار دیگر یک شیء BigDecimal ایجاد میکنم و اسم آنرا میگذارم bSum که مخفف big sum است.
و اینجا میخواهم آن مقادیر را با هم جمع کنم.
پس با bigValue شروع میکنم و بعد یک متد از این شیء با نام add را فراخوانی میکنم.
و متغیر bigValue را یکبار دیگر به آن میدهم و متد add یک شیء bigValue جدید برمیگرداند، پس میتوانم به سادگی متد add را یکبار دیگر صدا بزنم و مقدار bigValue را دوباره بدهم به آن.
حالا، bSum شده نتیجه دوبار اجرا عملیات جمع روی متغیر bigValue.
پس یکبار دیگر با Sout خروجی میگیریم ببینیم چه چیزی چاپ میشود.
اینبار میگویم که چاپ کند “Sum of BigDecimals:” و بعد bSum.toString را به آن اضافه میکنم.
دوستان دقت کنید نمیتوانید bSum را به تنهایی به عنوان یک شیء در خروجی چاپ کنید، چرا که نمیتواند طوری که شما میخواهید به عنوان یک رشته تفسیر شود. درست آن این است که، متد toString را فراخونی کنید، و این هم نتیجه کار.
جمعِ متغیرهای از جنسِ دابل با همدیگر بالاخره به درستی جواب داد، البته بعد از تبدیل آنها به رشته و بعد در آوردن آن رشتهها به شکل اشیا BigDecimal و در نهایت جمع آنها با همدیگر، و میبینیم که نتیجه به شکل دقیق و درستی درمیآید.
جمع بندی
این نکته خیلی مهم است که وقتی دارید با دادهها و مقادیرِ ارزی کار میکنید، یعنی جاهایی که دقت در مقدارهای عددی کاملاً حیاتی است و زمانی که کارتان به پول مربوط میشود، نمیتوانید آن مقدارهای خردهای را محاسبه کنید، چرا که درنهایت با جمع و تفریقِ همه آن مقادیرِ خردهای با هم، نتیجه درستی به شما داده نمیشود. پس در این مواقع مجبور هستید از کلاس BigDecimal برای بسته بندی این اعداد در کدهای جاوا خود استفاده کنید و در این صورت مطمئن باشید که نتیجه بدست آمده همیشه درست و دقیق خواهد بود.