ডাবল বনাম বিগডেসিমাল?


303

আমাকে কিছু ভাসমান বিন্দু ভেরিয়েবল গণনা করতে হবে এবং আমার সহকর্মী আমাকে আরও ব্যবহার BigDecimalকরার পরামর্শ দিচ্ছেন doubleএটি যেহেতু এটি আরও সুনির্দিষ্ট হবে। তবে আমি জানতে চাই যে এটি কী এবং কীভাবে সবচেয়ে বেশি ব্যবহার করা যায় BigDecimal?


উত্তর:


446

একটি BigDecimalসংখ্যার প্রতিনিধিত্ব একটি সঠিক উপায়। এ- Doubleএর একটি নির্দিষ্ট নির্ভুলতা রয়েছে। দ্বিগুণ বিভিন্ন মাত্রার সাথে কাজ করার ফলে (বলুন d1=1000.0এবং d2=0.001) 0.001পরিমাপের পার্থক্য এত বড় হওয়ায় সংক্ষিপ্তসার ঘটলে সামগ্রিকভাবে বাদ পড়তে পারে । BigDecimalএই সঙ্গে ঘটবে না।

এর অসুবিধা BigDecimalহ'ল এটি ধীর গতির এবং এ ভাবে অ্যালগরিদমগুলি প্রোগ্রাম করা ( ওভারলোড হওয়ার কারণে + - *এবং /না হওয়া) কিছুটা বেশি কঠিন ।

আপনি যদি অর্থের সাথে লেনদেন করছেন, বা নির্ভুলতা ব্যবহার করা আবশ্যক BigDecimal। অন্যথায় Doublesযথেষ্ট ভাল হতে থাকে।

আমি পড়া সুপারিশ করবেন javadoc এর BigDecimalহিসাবে তারা জিনিষ ভাল চেয়ে আমি এখানে করতে বর্ণনা করি :)


হ্যাঁ, আমি স্টকের দাম নির্ধারণ করছি তাই আমি বিশ্বাস করি যে বিগডিসিমাল এই ক্ষেত্রে দরকারী।
ট্রুং হা

5
@ ট্রুং হা: দামগুলির সাথে কাজ করার সময় আপনি বিগডিসিমালটি ব্যবহার করতে চান। এবং আপনি যদি এটি ডাটাবেসে সংরক্ষণ করেন তবে আপনি অনুরূপ কিছু চান।
এক্সারেনন

98
"বিগডিসিমাল সংখ্যার প্রতিনিধিত্ব করার সঠিক উপায়" বলে বিভ্রান্তিকর। 1/3 এবং 1/7 বেস 10 নম্বর সিস্টেমে (বিগডিসিমাল) বা বেস 2 নম্বর সিস্টেমে (ভাসা বা ডাবল) ঠিক প্রকাশ করা যায় না। 1/3 বেস 3, বেস 6, বেস 9, বেস 12 ইত্যাদি ঠিক প্রকাশ করা যেতে পারে এবং 1/7 বেস 7, বেস 14, বেস 21, ঠিক প্রকাশ করা যেতে পারে। বিগডিসিমাল সুবিধা হ'ল এটি নির্বিচারে নির্ভুলতা এবং যে মানুষের rounding ত্রুটি করতে ব্যবহার করা হয় আপনি বেস 10. পেতে
procrastinate_later

3
এটি ধীর হওয়া সম্পর্কে ভাল বক্তব্য, আমাকে বুঝতে সাহায্য করে যে নেটফ্লিক্স ফিতা লোড ব্যালেন্সার কোডটি ডাবলগুলির সাথে কেন আচরণ করে এবং তারপরে এর মতো লাইন রয়েছে:if (Math.abs(loadPerServer - maxLoadPerServer) < 0.000001d) {
মাইকেলেলোক

@ অ্যাক্সেট্রেন আমি মনে করি আপনি বলতে চাইছেন "যদি নির্ভুলতা আবশ্যক হয় তবে ব্যবহার করুন BigDecimal", একটি ডাবলটির আরও "নির্ভুলতা" (আরও অঙ্ক) থাকবে।
jspinella

164

আমার ইংরেজি ভাল নয় তাই আমি এখানে একটি সাধারণ উদাহরণ লিখব।

    double a = 0.02;
    double b = 0.03;
    double c = b - a;
    System.out.println(c);

    BigDecimal _a = new BigDecimal("0.02");
    BigDecimal _b = new BigDecimal("0.03");
    BigDecimal _c = _b.subtract(_a);
    System.out.println(_c);

প্রোগ্রাম আউটপুট:

0.009999999999999998
0.01

কেউ এখনও ডাবল ব্যবহার করতে চান? ;)


11
@eldjon Thats সত্য নয়, এই উদাহরণটি দেখুন: বিগডিসিমাল টু = নতুন বিগডিসিমাল ("2"); বিগডিসিমাল আট = নতুন বিগডিসিমাল ("8"); System.out.println (two.divide (আট)); এটি 0.25 প্রিন্ট করে।
লুডভিগ ডাব্লু

4
ডাবল অগ্রণী: ডি
ওয়াচ

তবুও যদি আপনি তার পরিবর্তে কোনও ফ্লোট ব্যবহার করেন তবে আপনি সেই ক্ষেত্রে বিগডিসিমালের চেয়ে একই সূক্ষ্মতা অর্জন করতে পারেন তবে আরও ভাল পারফরম্যান্সের উপায় পাবেন
এলিয়াক্স

3
@ ইলিউক্স ফ্লোট 0.03-0.02 এর সাথে কাজ করতে পারে তবে অন্যান্য মানগুলি এখনও System.out.println(0.003f - 0.002f);অপ্রচলিত : বিগডিসিমাল সঠিক:System.out.println(new BigDecimal("0.003").subtract(new BigDecimal("0.002")));
মার্টিন

50

ডাবল থেকে দুটি প্রধান পার্থক্য রয়েছে:

  • নির্বিচারে নির্ভুলতা, বিগআইন্টিজারের অনুরূপ এগুলি নির্বিচারে নির্ভুলতা এবং আকার ধারণ করতে পারে
  • বেস 2 এর পরিবর্তে বেস 10, একটি বিগডিসিমাল হল n * 10 ^ স্কেল যেখানে n একটি স্বেচ্ছাসেবীযুক্ত বড় স্বাক্ষরযুক্ত পূর্ণসংখ্যা এবং স্কেল দশমিক বিন্দু বাম বা ডান স্থানান্তরিত করতে অঙ্কের সংখ্যা হিসাবে বিবেচনা করা যেতে পারে

মুদ্রা গণনার জন্য আপনার বিগডিসিমাল ব্যবহার করার কারণ এটি নয় যে এটি কোনও সংখ্যাকে উপস্থাপন করতে পারে, তবে এটি দশমিক ধারণায় প্রতিনিধিত্ব করা যায় এমন সমস্ত সংখ্যাকে উপস্থাপন করতে পারে এবং আর্থিক জগতের কার্যত সমস্ত সংখ্যা অন্তর্ভুক্ত করে (আপনি কখনই স্থানান্তর করেন না 1/3 $ কারো প্রতি).


2
এই উত্তরটি সত্যই বিগডিসিমালকে ডাবল ওভার ব্যবহারের পার্থক্য এবং কারণ ব্যাখ্যা করে। পারফরম্যান্স উদ্বেগ গৌণ।
আবর্ত

এটি 100% সত্য নয়। আপনি লিখেছেন যে একটি বিগডিসিমাল হ'ল "এন * 10 ^ স্কেল"। জাভা কেবল নেতিবাচক সংখ্যার জন্য এটি করে। সুতরাং সঠিক হবে: "আনস্কেলডভ্যালু × 10 sc -স্কেল"। ধনাত্মক সংখ্যার জন্য বিগডিসিমাল একটি "স্বেচ্ছাসেবী যথার্থ পূর্ণসংখ্যার অবিচ্ছিন্ন মান এবং একটি 32-বিট পূর্ণসংখ্যার স্কেল" সমন্বিত করে যেখানে স্কেল দশমিক বিন্দুর ডানদিকে অঙ্কের সংখ্যা।
এনওডির

25

আপনি যদি 1 / 7দশমিক মান হিসাবে ভগ্নাংশের মান লিখেন

1/7 = 0.142857142857142857142857142857142857142857...

অসীম অনুক্রম সঙ্গে 142857। যেহেতু আপনি কেবল অঙ্কের একটি সীমাবদ্ধ সংখ্যা লিখতে পারেন তাই আপনি অনিবার্যভাবে একটি বৃত্তাকার (বা ছাঁটাই) ত্রুটি প্রবর্তন করবেন।

ভগ্নাংশের সাথে বাইনারি সংখ্যার মতো 1/10বা 1/100প্রকাশিত সংখ্যাগুলির দশমিক বিন্দুর পরেও অসীম সংখ্যা থাকে:

1/10 = binary 0.0001100110011001100110011001100110...

Doubles বাইনারি হিসাবে স্টোরের মানগুলি এবং তাই কোনও গাণিতিক না করে দশমিক সংখ্যাটিকে বাইনারি সংখ্যায় রূপান্তর করে কেবল ত্রুটি প্রবর্তন করতে পারে।

BigDecimalঅন্যদিকে দশমিক সংখ্যা (যেমন ) প্রতিটি দশমিক অঙ্ক যেমন থাকে তেমন সংরক্ষণ করুন। এর অর্থ হ'ল একটি দশমিক প্রকারটি বাইনারি ভাসমান বিন্দু বা সাধারণ অর্থে স্থির বিন্দুর ধরণের চেয়ে বেশি সুনির্দিষ্ট নয় ( 1/7তবে এটি নির্ভুলতার ক্ষতি ছাড়াই সঞ্চয় করতে পারে না ) তবে এটি সংখ্যার জন্য আরও সঠিক যা দশমিক সংখ্যা হিসাবে সীমাবদ্ধ সংখ্যা রয়েছে অর্থ গণনার ক্ষেত্রে প্রায়শই কেস হয়।

জাভা এর BigDecimalঅতিরিক্ত সুবিধা রয়েছে যে এটি কেবলমাত্র উপলব্ধ স্মৃতি দ্বারা সীমাবদ্ধ দশমিক পয়েন্টের উভয় পক্ষের একটি স্বেচ্ছাসেবী (তবে সসীম) সংখ্যা থাকতে পারে।


7

বিগডিসিমাল হ'ল ওরাকলের স্বেচ্ছাসেবী-নির্ভুলতার সংখ্যাসূচক গ্রন্থাগার। বিগডিসিমাল জাভা ভাষার অংশ এবং এটি আর্থিক থেকে শুরু করে বৈজ্ঞানিক পর্যন্ত বিভিন্ন অ্যাপ্লিকেশনের জন্য কার্যকর (সেখানকার প্রকারের am)।

নির্দিষ্ট গণনার জন্য ডাবল ব্যবহারে কোনও ভুল নেই। মনে করুন, তবে আপনি ম্যাথ গণনা করতে চেয়েছিলেন i পাই * ম্যাথ.পি / 6, অর্থাৎ, দুটি আসল যুক্তির জন্য রিমন জেটা ফাংশনের মান (আমি বর্তমানে একটি প্রকল্প যা নিয়ে কাজ করছি) ভাসমান-পয়েন্ট বিভাগটি আপনাকে রাউন্ডিং ত্রুটির বেদনাদায়ক সমস্যার সাথে উপস্থাপন করে।

অন্যদিকে বিগডিসিমালে স্বেচ্ছাসেবীর নির্ভুলতার জন্য এক্সপ্রেশন গণনা করার জন্য অনেকগুলি বিকল্প অন্তর্ভুক্ত করে। +, *, এবং / বিগডিসিমাল জাভা ওয়ার্ল্ডে "স্থান নিন" এর নীচে ওরাকল ডকুমেন্টেশনে বর্ণিত পদ্ধতিগুলি যুক্ত করুন, গুণ করুন এবং ভাগ করুন:

http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html

তুলনামূলক পদ্ধতিটি যখন এবং লুপগুলির জন্য বিশেষত কার্যকর।

বিগডিসিমালের জন্য আপনার কনস্ট্রাক্টর ব্যবহারের ক্ষেত্রে অবশ্যই সাবধান হন। স্ট্রিং কনস্ট্রাক্টর অনেক ক্ষেত্রেই খুব কার্যকর। উদাহরণস্বরূপ, কোড

বিগডিসিমাল অনেথার্ড = নতুন বিগডিসিমাল ("0.33333333333");

সেই অসীম-পুনরাবৃত্তি সংখ্যাকে নির্ভুলতার নির্দিষ্ট ডিগ্রিতে প্রতিনিধিত্ব করতে 1/3 এর স্ট্রিং প্রতিনিধিত্ব ব্যবহার করে। রাউন্ড-অফ ত্রুটিটি সম্ভবত জেভিএম-এর ভিতরে কোথাও এত গভীর ছিল যে রাউন্ড-অফ ত্রুটিগুলি আপনার বেশিরভাগ ব্যবহারিক গণনাগুলিকে বিরক্ত করবে না। আমি অবশ্য ব্যক্তিগত অভিজ্ঞতা থেকে দেখেছি, তবে গোল চক্কর মেরে উঠছে। ওরেটল ডকুমেন্টেশন থেকে দেখা যায়, এই সম্পর্কিত ক্ষেত্রে সেটস্কেল পদ্ধতিটি গুরুত্বপূর্ণ।


BigDecimal হয় অংশ এর জাভার অবাধ-স্পষ্টতা সংখ্যাসূচক গ্রন্থাগার। 'ইন-হাউস' এই প্রসঙ্গে অর্থহীন, বিশেষত এটি আইবিএম দ্বারা লেখা হয়েছিল।
মারকুইস

@ ইজেপি: আমি বিগডিসিমাল ক্লাসে দেখেছি এবং শিখেছি যে এর কেবলমাত্র অংশ আইবিএম লিখেছেন। কপিরাইট নীচে মন্তব্য: /* * Portions Copyright IBM Corporation, 2001. All Rights Reserved. */
realPK

7

আপনি যদি গণনা নিয়ে কাজ করছেন, আপনার কীভাবে গণনা করা উচিত এবং কোন নির্ভুলতা আপনার ব্যবহার করা উচিত সে সম্পর্কে আইন রয়েছে। যদি আপনি ব্যর্থ হন তবে আপনি কিছু অবৈধ কাজ করবেন। একমাত্র আসল কারণ হ'ল দশমিক মামলার বিট উপস্থাপনা সুনির্দিষ্ট নয়। যেমন তুলসী সহজভাবে বলা যায়, একটি উদাহরণ সর্বোত্তম ব্যাখ্যা। কেবল তার উদাহরণ পরিপূরক করতে, এখানে যা ঘটেছিল তা এখানে:

static void theDoubleProblem1() {
    double d1 = 0.3;
    double d2 = 0.2;
    System.out.println("Double:\t 0,3 - 0,2 = " + (d1 - d2));

    float f1 = 0.3f;
    float f2 = 0.2f;
    System.out.println("Float:\t 0,3 - 0,2 = " + (f1 - f2));

    BigDecimal bd1 = new BigDecimal("0.3");
    BigDecimal bd2 = new BigDecimal("0.2");
    System.out.println("BigDec:\t 0,3 - 0,2 = " + (bd1.subtract(bd2)));
}

আউটপুট:

Double:  0,3 - 0,2 = 0.09999999999999998
Float:   0,3 - 0,2 = 0.10000001
BigDec:  0,3 - 0,2 = 0.1

এছাড়াও আমাদের তা আছে:

static void theDoubleProblem2() {
    double d1 = 10;
    double d2 = 3;
    System.out.println("Double:\t 10 / 3 = " + (d1 / d2));

    float f1 = 10f;
    float f2 = 3f;
    System.out.println("Float:\t 10 / 3 = " + (f1 / f2));

    // Exception! 
    BigDecimal bd3 = new BigDecimal("10");
    BigDecimal bd4 = new BigDecimal("3");
    System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4)));
}

আমাদের আউটপুট দেয়:

Double:  10 / 3 = 3.3333333333333335
Float:   10 / 3 = 3.3333333
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion

কিন্তু:

static void theDoubleProblem2() {
    BigDecimal bd3 = new BigDecimal("10");
    BigDecimal bd4 = new BigDecimal("3");
    System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4, 4, BigDecimal.ROUND_HALF_UP)));
}

আউটপুট আছে:

BigDec:  10 / 3 = 3.3333 
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.