আমাকে সর্বদা বলা হয়েছে যে কখনও অর্থ double
বা float
প্রকারের সাথে প্রতিনিধিত্ব করবেন না এবং এবার আমি আপনার কাছে প্রশ্ন উত্থাপন করছি: কেন?
আমি নিশ্চিত যে খুব ভাল কারণ আছে, আমি কেবল এটি জানি না।
আমাকে সর্বদা বলা হয়েছে যে কখনও অর্থ double
বা float
প্রকারের সাথে প্রতিনিধিত্ব করবেন না এবং এবার আমি আপনার কাছে প্রশ্ন উত্থাপন করছি: কেন?
আমি নিশ্চিত যে খুব ভাল কারণ আছে, আমি কেবল এটি জানি না।
উত্তর:
কারণ ফ্লোটস এবং ডাবলস আমরা অর্থের জন্য ব্যবহার করি বেস 10 গুণগুলি সঠিকভাবে উপস্থাপন করতে পারে না। এই সমস্যাটি কেবল জাভার নয়, এটি এমন কোনও প্রোগ্রামিং ভাষার জন্য যা বেস 2 ভাসমান-পয়েন্টের ধরণের ব্যবহার করে।
বেস 10 এ, আপনি 1025 * 10 -2 হিসাবে 10.25 লিখতে পারেন ( 10 এর একটি পূর্ণসংখ্যার বার গুণ)। আইইইই-754৪ ভাসমান-পয়েন্ট সংখ্যাগুলি পৃথক, তবে তাদের সম্পর্কে ভাবার একটি খুব সহজ উপায় হ'ল পরিবর্তে দুটি দ্বারা গুণিত করা। উদাহরণস্বরূপ, আপনি 164 * 2 -4 ( দুটি সংখ্যার পূর্ণসংখ্যার বার) এর দিকে তাকিয়ে থাকতে পারেন যা 10.25 এর সমান। সংখ্যাগুলি মেমোরিতে কীভাবে উপস্থাপিত হয় তা নয়, তবে গণিতের প্রভাবগুলিও একই।
এমনকি বেস 10 এ, এই স্বরলিপিটি সবচেয়ে সাধারণ ভগ্নাংশকে সঠিকভাবে উপস্থাপন করতে পারে না। উদাহরণস্বরূপ, আপনি 1/3 উপস্থাপন করতে পারবেন না: দশমিক প্রতিনিধিত্ব পুনরাবৃত্তি করছে (0.3.33 ...), সুতরাং কোনও সীমাবদ্ধ পূর্ণসংখ্যা নেই যা আপনি 10 এর পাওয়ার দ্বারা 1/3 পেতে গুণতে পারেন। আপনি ৩৩ এর একটি দীর্ঘ ক্রম এবং 333333333 * 10 এর মতো একটি ক্ষুদ্র ঘোষককে স্থির করতে পারেন -10 এর মতো , তবে এটি সঠিক নয়: আপনি যদি এটি 3 দিয়ে গুণ করেন তবে আপনি 1 পাবেন না।
যাইহোক, অর্থ গণনা করার উদ্দেশ্যে, কমপক্ষে দেশগুলির জন্য যাদের অর্থ মার্কিন ডলারের প্রস্থের অর্ডারের মধ্যে মূল্যবান হয়, সাধারণত আপনার প্রয়োজন সমস্ত হ'ল 10 এর গুণক সঞ্চয় করতে সক্ষম হবেন -2 এর গুণকগুলি , তাই এটি আসলে কোনও ব্যাপার নয় doesn't যে 1/3 উপস্থাপন করা যাবে না।
ফ্লোটস এবং ডাবলসের সমস্যা হ'ল বেশীরভাগ টাকা মত সংখ্যার একটি পূর্ণসংখ্যা গুন একটি সঠিক উপস্থাপনা 2. আসলে একটি শক্তি, 0 এবং 1 এর মধ্যে 0.01 একমাত্র গুণিতক (যা যখন ডিলিং গুরুত্বপূর্ণ হবে না অর্থের সাথে কারণ তারা পূর্ণসংখ্যার সেন্ট) যা আইইইই-75৫৪ বাইনারি ভাসমান-পয়েন্ট সংখ্যা হিসাবে ঠিক উপস্থাপন করা যেতে পারে 0, 0.25, 0.5, 0.75 এবং 1 অন্যান্য সমস্ত অল্প পরিমাণে বন্ধ রয়েছে। ০.৩৩৩৩৩৩ উদাহরণের সাদৃশ্য হিসাবে, আপনি যদি 0.1 এর জন্য ভাসমান-পয়েন্ট মান নেন এবং আপনি এটি 10 দিয়ে গুণ করেন তবে আপনি 1 পাবেন না।
একটি হিসাবে অর্থ উপস্থাপন করা double
বা float
সম্ভবত প্রথমে দেখতে ভাল হিসাবে সফ্টওয়্যার ক্ষুদ্র ত্রুটিগুলি সরিয়ে দেয়, তবে আপনি যেমন আরও সংযোজন, বিয়োগ, গুণ এবং বিয়োগ সংখ্যক বিভাজনগুলি সম্পাদন করেন ত্রুটিগুলি আরও জটিল হয়ে উঠবে এবং আপনি দৃশ্যমান মানের সাথে শেষ হবেন you'll সঠিক না. এটি অর্থের সাথে লেনদেনের জন্য ভাসমান এবং ডাবল অপর্যাপ্ত করে তোলে, যেখানে বেস 10 শক্তির বহুগুণের জন্য নিখুঁত নির্ভুলতা প্রয়োজন।
কোনও সমাধান যে কোনও ভাষাতেই কাজ করে তা হ'ল পরিবর্তে পূর্ণসংখ্যা এবং সেন্ট গণনা। উদাহরণস্বরূপ, 1025 হবে $ 10.25। বেশ কয়েকটি ভাষায় অর্থোপার্জনের জন্য অন্তর্নির্মিত প্রকার রয়েছে। অন্যগুলির মধ্যে, জাভা BigDecimal
ক্লাস রয়েছে, এবং সি # decimal
টাইপ রয়েছে।
1.0 / 10 * 10
1.0 এর মতো নাও হতে পারে।
ব্লচ, জে।, কার্যকর জাভা, ২ য় সংস্করণ, আইটেম 48:
float
এবংdouble
ধরনের বিশেষ করে আর্থিক হিসাব জন্য মন্দ উপযুক্ত কারণ এটা অসম্ভব হিসেবে 0.1 (অথবা দশ অন্য কোন নেতিবাচক ক্ষমতা) প্রতিনিধিত্ব করতেfloat
বাdouble
ঠিক।উদাহরণস্বরূপ, ধরুন আপনার কাছে $ 1.03 এবং আপনি 42c ব্যয় করেন। তুমি কত টাকা রেখেছ?
System.out.println(1.03 - .42);
প্রিন্ট আউট
0.6100000000000001
।এই সমস্যার সমাধান করার সঠিক উপায় ব্যবহার করা
BigDecimal
,int
বাlong
আর্থিক হিসাব জন্য।
যদিও BigDecimal
কিছু সতর্কতা রয়েছে (দয়া করে বর্তমানে গৃহীত উত্তর দেখুন)।
long a = 104
ডলারের পরিবর্তে সেন্টে গণনা এবং গণনা করুন।
BigDecimal
।
এটি নির্ভুলতার বিষয় নয়, এটি নির্ভুলতার বিষয়ও নয়। বেস 2 এর পরিবর্তে গণনার জন্য বেস 10 ব্যবহার করা মানুষের প্রত্যাশা পূরণের বিষয়টি উদাহরণস্বরূপ, আর্থিক গণনার জন্য দ্বিগুণ ব্যবহার করা কোনও গাণিতিক দিক থেকে "ভুল" এমন উত্তর তৈরি করে না, তবে এটি উত্তরগুলি তৈরি করতে পারে যা হ'ল আর্থিক দিক থেকে যা প্রত্যাশিত তা নয়।
এমনকি যদি আপনি আউটপুটের আগে শেষ মুহুর্তে আপনার ফলাফলগুলি সরিয়ে নেন, আপনি এখনও মাঝে মধ্যে ডাবলগুলি ব্যবহার করে ফল পেতে পারেন যা প্রত্যাশার সাথে মেলে না।
একটি ক্যালকুলেটর ব্যবহার করে, বা হাতে হাতে ফলাফল গণনা করা হচ্ছে, ঠিক 1.40 * 165 = 231। তবে অভ্যন্তরীণভাবে আমার সংকলক / অপারেটিং সিস্টেমের পরিবেশে ডাবলগুলি ব্যবহার করে এটি 230.99999 এর কাছাকাছি বাইনারি নম্বর হিসাবে সঞ্চিত হয় ... সুতরাং আপনি যদি সংখ্যাটি কেটে ফেলেন তবে আপনি 231 এর পরিবর্তে 230 পেয়ে যাবেন You আপনি কারণটি কাটানোর পরিবর্তে গোল করতে পারেন 231 এর কাঙ্ক্ষিত ফলাফল দিয়েছে That এটি সত্য, তবে বৃত্তাকারে সর্বদা কাটা কাটা জড়িত। আপনি যে কোনও রাউন্ডিং টেকনিক ব্যবহার করেন না কেন, এখনও এর মতো সীমানা পরিস্থিতি রয়েছে যা আপনি যখন এটির চারপাশের প্রত্যাশা করবেন তখন গোল হয়ে যাবে। এগুলি যথেষ্ট বিরল যে তারা প্রায়শই ক্যাজুয়াল পরীক্ষা বা পর্যবেক্ষণের মাধ্যমে খুঁজে পাওয়া যায় না। প্রত্যাশার মতো আচরণ করে না এমন ফলাফলের চিত্র তুলে ধরে উদাহরণগুলির জন্য অনুসন্ধান করতে আপনাকে কিছু কোড লিখতে হতে পারে।
ধরুন আপনি নিকটতম পয়সা থেকে কিছু পেতে চান। সুতরাং আপনি আপনার চূড়ান্ত ফলাফলটি গ্রহণ করুন, 100 দ্বারা গুণিত করুন, 0.5 যোগ করুন, ছাঁটাই করুন, তারপরে পেনিগুলিতে ফিরে আসতে 100 কে ফলাফল ভাগ করুন। আপনার সঞ্চিত অভ্যন্তরীণ নম্বরটি যদি 3.46499999 হয় .... তবে 3.465 এর পরিবর্তে, আপনি 3.3 এর পরিবর্তে 3.46 পেতে যাবেন যখন আপনি সংখ্যাটি নিকটতম পয়সাতে গোল করবেন। তবে আপনার বেস 10 গণনাগুলি ইঙ্গিত দিয়েছে যে উত্তরটি অবশ্যই 3.465 হওয়া উচিত, যা স্পষ্টভাবে 3.47 এর চেয়ে বেশি হওয়া উচিত, 3.46 এর নিচে নয়। আপনি আর্থিক গণনার জন্য দ্বিগুণ ব্যবহার করলে বাস্তব জীবনে মাঝে মধ্যে এই জাতীয় জিনিসগুলি ঘটে ally এটি বিরল, তাই এটি একটি সমস্যা হিসাবে প্রায়শই নজরে আসে তবে তা ঘটে happens
যদি আপনি দ্বিগুণের পরিবর্তে আপনার অভ্যন্তরীণ গণনার জন্য বেস 10 ব্যবহার করেন তবে উত্তরগুলি সর্বদা আপনার কোডে অন্য কোনও বাগ অনুমান করে মানুষের দ্বারা প্রত্যাশিত ঠিক হয়।
Math.round(0.49999999999999994)
1 ফেরত দেয় ?
আমি এর কিছু প্রতিক্রিয়া দেখে অস্থির হয়েছি। আমি মনে করি আর্থিক গণনায় ডাবল এবং ফ্লোটের একটি জায়গা আছে। অবশ্যই, অ-ভগ্নাংশের আর্থিক পরিমাণ যুক্ত এবং বিয়োগ করার সময় পূর্ণসংখ্যা শ্রেণি বা বিগডিসিমাল ক্লাস ব্যবহার করার সময় নির্ভুলতার কোনও ক্ষতি হবে না। তবে আরও জটিল ক্রিয়াকলাপ সম্পাদন করার সময়, আপনি প্রায়শই ফলাফলগুলি শেষ করেন যা বেশ কয়েকটি বা বহু দশমিক স্থানে চলে যায়, আপনি সংখ্যাগুলি কীভাবে সংরক্ষণ করেন তা নির্বিশেষে। সমস্যাটি হল আপনি কীভাবে ফলাফল উপস্থাপন করবেন।
যদি আপনার ফলাফলটি বৃত্তাকার এবং বৃত্তাকার হয়ে যাওয়ার মধ্যে সীমান্তরেখায় থাকে এবং শেষ পয়সাটি সত্যই গুরুত্বপূর্ণ হয় তবে আপনি সম্ভবত দর্শকদের বলবেন যে উত্তরটি প্রায় মাঝখানে রয়েছে - আরও দশমিক স্থান প্রদর্শন করে।
ডাবলসের সমস্যা এবং আরও অনেক কিছু ভাসমানের ক্ষেত্রে, যখন সেগুলি বড় সংখ্যক এবং অল্প সংখ্যক একত্রিত করতে ব্যবহৃত হয়। জাভাতে,
System.out.println(1000000.0f + 1.2f - 1000000.0f);
ফলাফল স্বরূপ
1.1875
ফ্লোট এবং ডাবলগুলি আনুমানিক। আপনি যদি একটি বিগডিসিমাল তৈরি করেন এবং কনস্ট্রাক্টরের কাছে একটি ফ্লোট পাস করেন আপনি দেখতে পাবেন যে ফ্লোটটি আসলে সমান:
groovy:000> new BigDecimal(1.0F)
===> 1
groovy:000> new BigDecimal(1.01F)
===> 1.0099999904632568359375
এটি সম্ভবত আপনি কীভাবে $ 1.01 উপস্থাপন করতে চান তা নয়।
সমস্যাটি হ'ল আইইইই স্পেকের সমস্ত ভগ্নাংশকে হুবহু উপস্থাপন করার উপায় নেই, এর মধ্যে কিছুগুলি পুনরাবৃত্তি ভগ্নাংশ হিসাবে শেষ হয় যাতে আপনি আনুমানিক ত্রুটিগুলি শেষ করেন। যেহেতু হিসাবরক্ষকরা পেনির ঠিক মতো জিনিস প্রকাশ করতে পছন্দ করে এবং গ্রাহকরা যদি তাদের বিল পরিশোধ করেন এবং অর্থ প্রদানের প্রক্রিয়া শেষে তারা প্রাপ্য হন তবে তারা বিরক্ত হবেন এবং তাদের কাছ থেকে ফি নেওয়া হয় বা তাদের অ্যাকাউন্টটি বন্ধ করতে না পারলে এটি ব্যবহার করা ভাল use দশমিক (সি # তে) বা জাভা.ম্যাথ.বিগডিসিমালের মতো যথাযথ প্রকারভেদ Java
আপনি যদি গোল করেন তবে ত্রুটিটি নিয়ন্ত্রণযোগ্য নয়: পিটার লরির এই নিবন্ধটি দেখুন । প্রথম স্থানে ঘোরাঘুরি না করাই সহজ। বেশিরভাগ অ্যাপ্লিকেশন যা অর্থ পরিচালনা করে তা প্রচুর গণিতের জন্য কল করে না, অপারেশনগুলিতে জিনিসগুলি যুক্ত করা বা বিভিন্ন বালতিতে পরিমাণ বরাদ্দ করে। ভাসমান পয়েন্ট এবং গোলাকার পরিচয় করিয়ে দেওয়া কেবল বিষয়গুলিকে জটিল করে তোলে।
float
, double
এবং সঠিক মান BigDecimal
উপস্থাপন করে । কোড টু অবজেক্ট কনভার্সেশন অপারেশন পাশাপাশি অন্যান্য ক্রিয়াকলাপ। প্রকারগুলি নিজেরাই নিখুঁত নয়।
আমি নিম্নমানের ঝুঁকি নিয়ে যাব, তবে আমি মনে করি মুদ্রার গণনার জন্য ভাসমান পয়েন্ট সংখ্যাগুলির অপ্রয়োজনীয়তা ওভাররেড হয়ে গেছে। যতক্ষণ আপনি জেনাক দ্বারা ব্যাখ্যা করা বাইনারি-দশমিক প্রতিনিধিত্বের অমিলটি মোকাবেলায় সঠিকভাবে সেন্ট-রাউন্ডিং করছেন এবং কাজ করার জন্য যথেষ্ট উল্লেখযোগ্য সংখ্যা রয়েছে তা নিশ্চিত করার পরেও কোনও সমস্যা হবে না।
এক্সেলে মুদ্রার সাথে গণনা করা লোকেরা সর্বদা ডাবল নির্ভুলতা ফ্লোট ব্যবহার করে থাকে (এক্সেলের কোনও মুদ্রার ধরণ নেই) এবং আমি এখনও কাউকে গোলাকার ত্রুটি সম্পর্কে অভিযোগ করতে দেখিনি।
অবশ্যই, আপনাকে কারণের মধ্যে থাকতে হবে; যেমন একটি সাধারণ ওয়েবশপ সম্ভবত ডাবল স্পষ্টতা ভাসমান নিয়ে কোনও সমস্যা অনুভব করতে পারে না, তবে আপনি যদি অ্যাকাউন্টিং বা এমন কোনও কিছু করেন যা সংখ্যার একটি বৃহত্তর (অনিয়ন্ত্রিত) সংযোজন দরকার হয়, আপনি দশ ফুট দিয়ে ভাসমান পয়েন্ট সংখ্যা স্পর্শ করতে চাইবেন না মেরু.
যদিও এটি সত্য যে ভাসমান পয়েন্টের ধরণটি কেবলমাত্র দশমিক ডেটা উপস্থাপন করতে পারে, এটিও সত্য যে কোনও একটি যদি সংখ্যাকে তাদের উপস্থাপনের আগে প্রয়োজনীয় নির্ভুলতার দিকে ঘুরিয়ে দেয় তবে সঠিক ফলাফলটি পাওয়া যায়। সাধারণত।
সাধারণত যেহেতু ডাবল টাইপটির সংক্ষিপ্ততা 16 টিরও কম। আপনার যদি আরও সঠিক নির্ভুলতার প্রয়োজন হয় তবে এটি উপযুক্ত ধরণের নয়। এছাড়াও আনুমানিক সংগ্রহ করতে পারে।
এটি অবশ্যই বলা উচিত যে আপনি নির্দিষ্ট পয়েন্ট পাটিগণিত ব্যবহার করার পরেও আপনাকে এখনও গোলাকার সংখ্যাগুলি করতে হবে, আপনি যদি পর্যায়ক্রমিক দশমিক সংখ্যা অর্জন করেন তবে বিগইন্টিজার এবং বিগডিসিমাল ত্রুটি দেয় তা কি সত্য নয়? সুতরাং এখানে একটি আনুমানিক হয়।
উদাহরণস্বরূপ, সিওবিএল, আর্থিক গণনার জন্য historতিহাসিকভাবে ব্যবহৃত, সর্বাধিক 18 পরিসংখ্যানের নির্ভুলতা রয়েছে। সুতরাং প্রায়শই একটি অন্তর্নিহিত বৃত্তাকার হয়।
উপসংহারে, আমার মতে ডাবলটি প্রায় 16 এর অঙ্কের নির্ভুলতার জন্য অনুপযুক্ত, যা অপ্রতুল হতে পারে, এটি আনুমানিক নয় বলে নয়।
পরবর্তী প্রোগ্রামের নিম্নলিখিত আউটপুটটি বিবেচনা করুন। এটি দেখায় যে ডাবল রাউন্ডিংয়ের পরে বিগডিসিমালের মতো একই ফলাফল যথাযথ 16 পর্যন্ত দেয়।
Precision 14
------------------------------------------------------
BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal : 56789.012345 / 1111111111 = 0.000051110111115611
Double : 56789.012345 / 1111111111 = 0.000051110111115611
Precision 15
------------------------------------------------------
BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal : 56789.012345 / 1111111111 = 0.0000511101111156110
Double : 56789.012345 / 1111111111 = 0.0000511101111156110
Precision 16
------------------------------------------------------
BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal : 56789.012345 / 1111111111 = 0.00005111011111561101
Double : 56789.012345 / 1111111111 = 0.00005111011111561101
Precision 17
------------------------------------------------------
BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal : 56789.012345 / 1111111111 = 0.000051110111115611011
Double : 56789.012345 / 1111111111 = 0.000051110111115611013
Precision 18
------------------------------------------------------
BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal : 56789.012345 / 1111111111 = 0.0000511101111156110111
Double : 56789.012345 / 1111111111 = 0.0000511101111156110125
Precision 19
------------------------------------------------------
BigDecimalNoRound : 56789.012345 / 1111111111 = Non-terminating decimal expansion; no exact representable decimal result.
DoubleNoRound : 56789.012345 / 1111111111 = 5.111011111561101E-5
BigDecimal : 56789.012345 / 1111111111 = 0.00005111011111561101111
Double : 56789.012345 / 1111111111 = 0.00005111011111561101252
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.MathContext;
public class Exercise {
public static void main(String[] args) throws IllegalArgumentException,
SecurityException, IllegalAccessException,
InvocationTargetException, NoSuchMethodException {
String amount = "56789.012345";
String quantity = "1111111111";
int [] precisions = new int [] {14, 15, 16, 17, 18, 19};
for (int i = 0; i < precisions.length; i++) {
int precision = precisions[i];
System.out.println(String.format("Precision %d", precision));
System.out.println("------------------------------------------------------");
execute("BigDecimalNoRound", amount, quantity, precision);
execute("DoubleNoRound", amount, quantity, precision);
execute("BigDecimal", amount, quantity, precision);
execute("Double", amount, quantity, precision);
System.out.println();
}
}
private static void execute(String test, String amount, String quantity,
int precision) throws IllegalArgumentException, SecurityException,
IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
Method impl = Exercise.class.getMethod("divideUsing" + test, String.class,
String.class, int.class);
String price;
try {
price = (String) impl.invoke(null, amount, quantity, precision);
} catch (InvocationTargetException e) {
price = e.getTargetException().getMessage();
}
System.out.println(String.format("%-30s: %s / %s = %s", test, amount,
quantity, price));
}
public static String divideUsingDoubleNoRound(String amount,
String quantity, int precision) {
// acceptance
double amount0 = Double.parseDouble(amount);
double quantity0 = Double.parseDouble(quantity);
//calculation
double price0 = amount0 / quantity0;
// presentation
String price = Double.toString(price0);
return price;
}
public static String divideUsingDouble(String amount, String quantity,
int precision) {
// acceptance
double amount0 = Double.parseDouble(amount);
double quantity0 = Double.parseDouble(quantity);
//calculation
double price0 = amount0 / quantity0;
// presentation
MathContext precision0 = new MathContext(precision);
String price = new BigDecimal(price0, precision0)
.toString();
return price;
}
public static String divideUsingBigDecimal(String amount, String quantity,
int precision) {
// acceptance
BigDecimal amount0 = new BigDecimal(amount);
BigDecimal quantity0 = new BigDecimal(quantity);
MathContext precision0 = new MathContext(precision);
//calculation
BigDecimal price0 = amount0.divide(quantity0, precision0);
// presentation
String price = price0.toString();
return price;
}
public static String divideUsingBigDecimalNoRound(String amount, String quantity,
int precision) {
// acceptance
BigDecimal amount0 = new BigDecimal(amount);
BigDecimal quantity0 = new BigDecimal(quantity);
//calculation
BigDecimal price0 = amount0.divide(quantity0);
// presentation
String price = price0.toString();
return price;
}
}
ভাসমান পয়েন্ট সংখ্যার ফলাফলটি সঠিক নয়, যা তাদেরকে এমন কোনও আর্থিক গণনার জন্য অনুপযুক্ত করে তোলে যার সঠিক ফলাফল প্রয়োজন এবং না প্রায় not ভাসা এবং ডাবল ইঞ্জিনিয়ারিং এবং বৈজ্ঞানিক গণনার জন্য ডিজাইন করা হয়েছে এবং অনেক সময় সঠিক ফলাফলও দেয় না ভাসমান পয়েন্ট গণনার ফলাফলও জেভিএম থেকে জেভিএমে পরিবর্তিত হতে পারে। বিগডিসিমাল এবং ডাবল আদিম এর নীচের উদাহরণটি দেখুন যা অর্থের মান উপস্থাপনের জন্য ব্যবহৃত হয়, এটি একেবারে স্পষ্ট যে ভাসমান পয়েন্ট গণনা সঠিক নাও হতে পারে এবং আর্থিক গণনার জন্য বিগডিসিমাল ব্যবহার করা উচিত।
// floating point calculation
final double amount1 = 2.0;
final double amount2 = 1.1;
System.out.println("difference between 2.0 and 1.1 using double is: " + (amount1 - amount2));
// Use BigDecimal for financial calculation
final BigDecimal amount3 = new BigDecimal("2.0");
final BigDecimal amount4 = new BigDecimal("1.1");
System.out.println("difference between 2.0 and 1.1 using BigDecimal is: " + (amount3.subtract(amount4)));
আউটপুট:
difference between 2.0 and 1.1 using double is: 0.8999999999999999
difference between 2.0 and 1.1 using BigDecimal is: 0.9
double
শতাংশে বাইনারি এফপি ব্যবহার করে 0.5 শতাংশ হিসাবে গণনা করতে কোনও সমস্যা হবে না কারণ দশমিক এফপিও নয়। যদি ফ্লোটিং-পয়েন্ট গণনাগুলি 123.499941 eg যেমন একটি বাইনারি এফপি বা দশমিক এফপির মাধ্যমে, এর সুদের মান অর্জন করে তবে ডাবল রাউন্ডিং সমস্যাটি একই - কোনওভাবেই কোনও সুবিধা হবে না। আপনার ভিত্তিটি গাণিতিক-নির্ভুল মান ধরেছে এবং দশমিক এফপি এক হিসাবে মনে হচ্ছে - এমন কি দশমিক এফপিও গ্যারান্টি দেয় না। 0.5 / 7.0 * 7.0 বাইনারি এবং ডিকমাল এফপির ক্ষেত্রে সমস্যা। আইএসি, সিটির পরবর্তী সংস্করণটি দশমিক এফপি সরবরাহ করবে বলে আমি প্রত্যাশা করায় বেশিরভাগই মোট হবে।
যেমনটি আগে বলা হয়েছিল "ডাবল বা ভাসমান হিসাবে অর্থ উপস্থাপন করা সম্ভবত সফ্টওয়্যারটির ক্ষুদ্র ত্রুটিগুলি সরিয়ে দেয় তবে আপনি যথাযথ সংখ্যায় আরও সংযোজন, বিয়োগ, গুণ এবং বিভাগগুলি সম্পাদন করার ফলে আপনি আরও এবং আরও নির্ভুলতা হারাবেন ত্রুটিগুলি যুক্ত হওয়ার সাথে সাথে এটি অর্থের সাথে লেনদেনের জন্য ভাসমান এবং দ্বিগুণ অপর্যাপ্ত করে তোলে, যেখানে বেস 10 শক্তির বহুগুণের জন্য নিখুঁত নির্ভুলতা প্রয়োজন ""
অবশেষে জাভা মুদ্রা এবং অর্থ দিয়ে কাজ করার একটি স্ট্যান্ডার্ড উপায় আছে!
জেএসআর 354: অর্থ এবং মুদ্রার এপিআই
জেএসআর 354 অর্থ এবং মুদ্রার সাথে ব্যাপক গণনা উপস্থাপন, পরিবহন এবং সম্পাদনের জন্য একটি এপিআই সরবরাহ করে। আপনি এই লিঙ্ক থেকে এটি ডাউনলোড করতে পারেন:
জেএসআর 354: অর্থ এবং মুদ্রার এপিআই ডাউনলোড করুন
স্পেসিফিকেশন নিম্নলিখিত জিনিস নিয়ে গঠিত:
- হ্যান্ডলিংয়ের জন্য একটি API যেমন আর্থিক পরিমাণ এবং মুদ্রা
- বিনিময়যোগ্য প্রয়োগগুলি সমর্থন করার জন্য API গুলি
- বাস্তবায়ন ক্লাসগুলির উদাহরণ তৈরির কারখানাগুলি
- গণনা, রূপান্তর এবং আর্থিক পরিমাণের বিন্যাসকরণের জন্য কার্যকারিতা
- মানি এবং মুদ্রার সাথে কাজ করার জন্য জাভা এপিআই, যা জাভা 9 এ অন্তর্ভুক্ত করার পরিকল্পনা করা হয়েছে।
- সমস্ত স্পেসিফিকেশন ক্লাস এবং ইন্টারফেস javax.money। * প্যাকেজে অবস্থিত।
জেএসআর 354 এর নমুনা উদাহরণ: অর্থ এবং মুদ্রার এপিআই:
মুদ্রাআমাউন্ট তৈরি করার এবং কনসোলে এটি মুদ্রণের উদাহরণটি দেখতে এরকম দেখাচ্ছে:
MonetaryAmountFactory<?> amountFactory = Monetary.getDefaultAmountFactory();
MonetaryAmount monetaryAmount = amountFactory.setCurrency(Monetary.getCurrency("EUR")).setNumber(12345.67).create();
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));
রেফারেন্স বাস্তবায়ন এপিআই ব্যবহার করার সময়, প্রয়োজনীয় কোডটি অনেক সহজ:
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));
এপিআই মনিটারিঅ্যামাউন্টস সহ গণনাগুলি সমর্থন করে:
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmount otherMonetaryAmount = monetaryAmount.divide(2).add(Money.of(5, "EUR"));
কারেন্সিউইনিট এবং মুদ্রাঅ্যামাউন্ট
// getting CurrencyUnits by locale
CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN);
CurrencyUnit canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);
মানিটারাউন্টে বিভিন্ন পদ্ধতি রয়েছে যা নির্ধারিত মুদ্রা, সংখ্যার পরিমাণ, তার যথার্থতা এবং আরও অনেক কিছু অ্যাক্সেসের অনুমতি দেয়:
MonetaryAmount monetaryAmount = Money.of(123.45, euro);
CurrencyUnit currency = monetaryAmount.getCurrency();
NumberValue numberValue = monetaryAmount.getNumber();
int intValue = numberValue.intValue(); // 123
double doubleValue = numberValue.doubleValue(); // 123.45
long fractionDenominator = numberValue.getAmountFractionDenominator(); // 100
long fractionNumerator = numberValue.getAmountFractionNumerator(); // 45
int precision = numberValue.getPrecision(); // 5
// NumberValue extends java.lang.Number.
// So we assign numberValue to a variable of type Number
Number number = numberValue;
MonetaryAmounts একটি বৃত্তাকার অপারেটর ব্যবহার করে বৃত্তাকার করা যেতে পারে:
CurrencyUnit usd = MonetaryCurrencies.getCurrency("USD");
MonetaryAmount dollars = Money.of(12.34567, usd);
MonetaryOperator roundingOperator = MonetaryRoundings.getRounding(usd);
MonetaryAmount roundedDollars = dollars.with(roundingOperator); // USD 12.35
মানিএমাউন্টগুলির সংগ্রহের সাথে কাজ করার সময়, ফিল্টারিং, বাছাই এবং গোষ্ঠীকরণের জন্য কয়েকটি দুর্দান্ত ইউটিলিটি পদ্ধতি উপলব্ধ।
List<MonetaryAmount> amounts = new ArrayList<>();
amounts.add(Money.of(2, "EUR"));
amounts.add(Money.of(42, "USD"));
amounts.add(Money.of(7, "USD"));
amounts.add(Money.of(13.37, "JPY"));
amounts.add(Money.of(18, "USD"));
কাস্টম মানিঅ্যামাউন্ট ক্রিয়াকলাপ
// A monetary operator that returns 10% of the input MonetaryAmount
// Implemented using Java 8 Lambdas
MonetaryOperator tenPercentOperator = (MonetaryAmount amount) -> {
BigDecimal baseAmount = amount.getNumber().numberValue(BigDecimal.class);
BigDecimal tenPercent = baseAmount.multiply(new BigDecimal("0.1"));
return Money.of(tenPercent, amount.getCurrency());
};
MonetaryAmount dollars = Money.of(12.34567, "USD");
// apply tenPercentOperator to MonetaryAmount
MonetaryAmount tenPercentDollars = dollars.with(tenPercentOperator); // USD 1.234567
সম্পদ:
জেএসআর 354 এর সাহায্যে জাভাতে অর্থ এবং মুদ্রা পরিচালনা করা
জাভা 9 অর্থ এবং মুদ্রার এপিআই (জেএসআর 354) সন্ধান করছেন
আরও দেখুন: জেএসআর 354 - মুদ্রা এবং অর্থ
যদি আপনার গণনায় বিভিন্ন পদক্ষেপ জড়িত থাকে, স্বেচ্ছাচারিত নির্ভুলতা পাটিগণিত আপনাকে 100% কভার করবে না।
ফলাফলের নিখুঁত উপস্থাপনা ব্যবহারের একমাত্র নির্ভরযোগ্য উপায় (একটি কাস্টম ভগ্নাংশ ডেটা ব্যবহার করুন যা বিভাগের ক্রিয়াকে শেষ ধাপে ব্যাচ করবে) এবং কেবলমাত্র শেষ ধাপে দশমিক স্বীকৃতিতে রূপান্তরিত।
স্বেচ্ছাসেবক নির্ভুলতা সাহায্য করবে না কারণ সর্বদা এমন সংখ্যা থাকতে পারে যেখানে এতগুলি দশমিক স্থান থাকে বা কিছু ফলাফল যেমন 0.6666666
... কোনও নির্বিচারে উপস্থাপনা শেষ উদাহরণটি আবরণ করে না। সুতরাং আপনার প্রতিটি পদক্ষেপে ছোট ছোট ত্রুটি থাকবে।
এই ত্রুটিগুলি অ্যাড আপ হবে, শেষ পর্যন্ত আর এড়ানো সহজ হবে না become একে ত্রুটি প্রচার বলে ।
অর্থ এবং মুদ্রার গণনার জন্য কারো দ্বিগুণ ব্যবহার করা উচিত নয় কেন তা বেশিরভাগ উত্তরে হাইলাইট করেছে। এবং আমি তাদের সাথে সম্পূর্ণ একমত
যদিও এর অর্থ এই নয় যে ডাবলগুলি কখনই সেই উদ্দেশ্যে ব্যবহার করা যায় না।
আমি খুব কম জিসি প্রয়োজনীয়তা সহ বেশ কয়েকটি প্রকল্পে কাজ করেছি এবং বিগডিসিমাল অবজেক্টগুলি সেই ওভারহেডে বড় অবদানকারী ছিল।
এটি দ্বিগুণ প্রতিনিধিত্ব সম্পর্কে বোঝার অভাব এবং যথাযথতা এবং নির্ভুলতা পরিচালনা করার অভিজ্ঞতার অভাব যা এই বিজ্ঞ পরামর্শটি নিয়ে আসে।
আপনি যদি আপনার প্রকল্পের যথাযথতা এবং নির্ভুলতার প্রয়োজনীয়তাগুলি পরিচালনা করতে সক্ষম হন তবে আপনি এটি কার্যকর করতে পারেন, যা দ্বিগুণ মানের পরিসীমা নিয়ে কাজ করে তার উপর ভিত্তি করে সম্পন্ন করতে হয়।
আপনি আরও ধারণা পেতে পেয়ারার ফাজি কম্পিউটার পদ্ধতিটি দেখুন। প্যারামিটার সহনশীলতা মূল। সিকিওরিটি ট্রেডিং অ্যাপ্লিকেশনের জন্য আমরা এই সমস্যাটি মোকাবিলা করেছি এবং আমরা বিভিন্ন পরিসরে বিভিন্ন সংখ্যাগত মানগুলির জন্য কী ব্যবহার সহ্য করতে পারে সে সম্পর্কে একটি বিস্তৃত গবেষণা করেছি।
এছাড়াও, এমন পরিস্থিতিতে থাকতে পারে যখন আপনি হ্যাশ ম্যাপের বাস্তবায়ন হিসাবে মানচিত্র কী হিসাবে ডাবল মোড়ক ব্যবহার করতে প্ররোচিত হন। এটি অত্যন্ত ঝুঁকিপূর্ণ কারণ ডাবল.এক্কালস এবং হ্যাশ কোড উদাহরণস্বরূপ "0.5" এবং "0.6 - 0.1" মানসিক চাপ সৃষ্টি করবে।
এই প্রশ্নের পোস্ট করা অনেক উত্তর আইইইই এবং ভাসমান-পয়েন্ট পাটিগণিতের চারপাশের মানদণ্ডগুলি নিয়ে আলোচনা করে।
একটি কম্পিউটারবিহীন বিজ্ঞান পটভূমি (পদার্থবিজ্ঞান এবং প্রকৌশল) থেকে এসে আমি সমস্যাগুলিকে অন্য দৃষ্টিকোণ থেকে দেখার প্রবণতা করি। আমার জন্য, যে কারণে আমি গাণিতিক গণনায় ডাবল বা ভাসমান ব্যবহার করব না তা হ'ল আমি খুব বেশি তথ্য হারাব।
বিকল্পগুলি কি? এখানে অনেকগুলি (এবং আরও অনেক কিছুই আমি অবগত নই!)।
জাভাতে বিগডিসিমাল জাভা ভাষার স্থানীয়। অ্যাপফ্লোট জাভা-র জন্য আরেকটি নির্বিচার-যথার্থ গ্রন্থাগার।
সি # তে দশমিক ডেটা টাইপ হ'ল 28 টি গুরুত্বপূর্ণ ব্যক্তির জন্য মাইক্রোসফ্টের .NET বিকল্প।
SciPy (বৈজ্ঞানিক পাইথন) সম্ভবত আর্থিক গণনাও পরিচালনা করতে পারে (আমি চেষ্টা করি নি, তবে আমার সন্দেহ হয়)।
জিএনইউ মাল্টিপল প্রিসিন লাইব্রেরি (জিএমপি) এবং জিএনইউ এমএফপিআর লাইব্রেরি সি এবং সি ++ এর জন্য দুটি ফ্রি এবং ওপেন-সোর্স রিসোর্স।
জাভাস্ক্রিপ্ট (!) এর জন্য সংখ্যাগত নির্ভুলতা গ্রন্থাগারগুলিও রয়েছে এবং আমি মনে করি পিএইচপি যা আর্থিক গণনা পরিচালনা করতে পারে।
মালিকানাধীন (বিশেষত, আমি মনে করি, ফরট্রানের জন্য) এবং অনেকগুলি কম্পিউটার ভাষার জন্য ওপেন-সোর্স সমাধানও রয়েছে।
প্রশিক্ষণ নিয়ে আমি কম্পিউটার বিজ্ঞানী নই। যাইহোক, আমি জাভাতে বিগডিসিমাল বা সি # তে দশমিকের দিকে ঝুঁকতে চাই। আমি তালিকাভুক্ত অন্যান্য সমাধানগুলি চেষ্টা করে দেখিনি, তবে সেগুলি সম্ভবত খুব ভাল।
আমার জন্য, আমি বিগডিসিমাল পছন্দ করি কারণ এটি যে পদ্ধতিগুলি সমর্থন করে। সি # এর দশমিকটি খুব সুন্দর, তবে আমি যতটা চাই তার সাথে কাজ করার সুযোগ পাইনি। আমি আমার অতিরিক্ত সময়টিতে আমার কাছে আগ্রহের বৈজ্ঞানিক গণনা করি এবং বিগডিসিমাল খুব ভালভাবে কাজ করে বলে মনে হয় কারণ আমি আমার ভাসমান পয়েন্ট সংখ্যাগুলির যথার্থতা নির্ধারণ করতে পারি। বিগডিসিমালের অসুবিধা? এটি সময়ে সময়ে ধীর হতে পারে, বিশেষত যদি আপনি বিভাজন পদ্ধতিটি ব্যবহার করেন।
আপনি, গতির জন্য, সি, সি ++ এবং ফোর্টরানের বিনামূল্যে এবং মালিকানাধীন গ্রন্থাগারগুলি সন্ধান করতে পারেন।
পূর্ববর্তী উত্তরগুলি যুক্ত করার জন্য, জোদা-মানি প্রয়োগের বিকল্পও রয়েছে প্রশ্নে সম্বোধন করা সমস্যাটি মোকাবেলা করার সময় বিগডেসিমাল ছাড়াও জাভাতে । জাভা মডুলের নাম org.joda.money।
এটি জাভা এসই 8 বা তার পরে প্রয়োজন এবং এর কোনও নির্ভরতা নেই।
আরও সুনির্দিষ্টভাবে বলতে গেলে, সংকলন-সময় নির্ভরতা রয়েছে তবে এটির প্রয়োজন নেই।
<dependency>
<groupId>org.joda</groupId>
<artifactId>joda-money</artifactId>
<version>1.0.1</version>
</dependency>
জোদা মানি ব্যবহারের উদাহরণ:
// create a monetary value
Money money = Money.parse("USD 23.87");
// add another amount with safe double conversion
CurrencyUnit usd = CurrencyUnit.of("USD");
money = money.plus(Money.of(usd, 12.43d));
// subtracts an amount in dollars
money = money.minusMajor(2);
// multiplies by 3.5 with rounding
money = money.multipliedBy(3.5d, RoundingMode.DOWN);
// compare two amounts
boolean bigAmount = money.isGreaterThan(dailyWage);
// convert to GBP using a supplied rate
BigDecimal conversionRate = ...; // obtained from code outside Joda-Money
Money moneyGBP = money.convertedTo(CurrencyUnit.GBP, conversionRate, RoundingMode.HALF_UP);
// use a BigMoney for more complex calculations where scale matters
BigMoney moneyCalc = money.toBigMoney();
ডকুমেন্টেশন: http://joda-money.sourceforge.net/apidocs/org/joda/money/Money.html
বাস্তবায়ন উদাহরণগুলি: https://www.programcreek.com/java-api-example/?api=org.joda.money.Money
কিছু উদাহরণ ... এটি প্রায় কোনও প্রোগ্রামিং ভাষার ক্ষেত্রে (আসলে প্রত্যাশার মতো কাজ করে না) কাজ করে ... আমি ডেলফি, ভিবিএস স্ক্রিপ্ট, ভিজ্যুয়াল বেসিক, জাভাস্ক্রিপ্ট এবং এখন জাভা / অ্যান্ড্রয়েড দিয়ে চেষ্টা করেছি:
double total = 0.0;
// do 10 adds of 10 cents
for (int i = 0; i < 10; i++) {
total += 0.1; // adds 10 cents
}
Log.d("round problems?", "current total: " + total);
// looks like total equals to 1.0, don't?
// now, do reverse
for (int i = 0; i < 10; i++) {
total -= 0.1; // removes 10 cents
}
// looks like total equals to 0.0, don't?
Log.d("round problems?", "current total: " + total);
if (total == 0.0) {
Log.d("round problems?", "is total equal to ZERO? YES, of course!!");
} else {
Log.d("round problems?", "is total equal to ZERO? NO... thats why you should not use Double for some math!!!");
}
আউটপুট:
round problems?: current total: 0.9999999999999999
round problems?: current total: 2.7755575615628914E-17
round problems?: is total equal to ZERO? NO... thats why you should not use Double for some math!!!
বিভিন্ন নকশার সাথে ভাসাটি দশমিকের বাইনারি রূপ; তারা দুটি ভিন্ন জিনিস. একে অপরের সাথে রূপান্তরিত হওয়ার সময় দুটি ধরণের মধ্যে অল্প ত্রুটি রয়েছে। এছাড়াও, ভাসমানটি বৈজ্ঞানিক জন্য অসীম সংখ্যক মান উপস্থাপনের জন্য ডিজাইন করা হয়েছে। এর অর্থ এটি নির্দিষ্ট সংখ্যক বাইটের সাথে চূড়ান্ত ছোট এবং চরম সংখ্যক সংখ্যক স্পষ্টতা হারিয়ে যাওয়ার জন্য ডিজাইন করা হয়েছে। দশমিক হ'ল অসীম মানগুলির প্রতিনিধিত্ব করতে পারে না, এটি কেবলমাত্র দশমিক অঙ্কের সংখ্যায় সীমাবদ্ধ। সুতরাং ফ্লোট এবং ডেসিমাল বিভিন্ন উদ্দেশ্যে।
মুদ্রা মানটির জন্য ত্রুটিটি পরিচালনা করার কিছু উপায় রয়েছে:
পরিবর্তে দীর্ঘ পূর্ণসংখ্যা এবং সেন্টগুলিতে গণনা করুন।
দ্বিগুণ নির্ভুলতা ব্যবহার করুন, আপনার উল্লেখযোগ্য সংখ্যাগুলি কেবল 15 এ রাখুন যাতে দশমিকটি হুবহু অনুকরণ করা যায়। মান উপস্থাপনের আগে গোল; গণনা করার সময় প্রায়শই গোল হয়।
জাভা বিগডিসিমালের মতো দশমিক লাইব্রেরি ব্যবহার করুন যাতে দশমিকের অনুকরণের জন্য আপনার দ্বিগুণ ব্যবহারের প্রয়োজন হবে না।
PS এটি জেনে রাখা আকর্ষণীয় যে বেশিরভাগ ব্র্যান্ডের হ্যান্ডহেল্ড বৈজ্ঞানিক ক্যালকুলেটরগুলি ফ্লোটের পরিবর্তে দশমিকের উপরে কাজ করে। সুতরাং কারও অভিযোগ রূপান্তর ত্রুটি ভাসাচ্ছে না।