নিম্নলিখিত কোড বিবেচনা করুন:
0.1 + 0.2 == 0.3 -> false
0.1 + 0.2 -> 0.30000000000000004
কেন এই অনর্থক ঘটনা ঘটে?
নিম্নলিখিত কোড বিবেচনা করুন:
0.1 + 0.2 == 0.3 -> false
0.1 + 0.2 -> 0.30000000000000004
কেন এই অনর্থক ঘটনা ঘটে?
উত্তর:
বাইনারি ভাসমান পয়েন্ট গণিত এর মত। বেশিরভাগ প্রোগ্রামিং ভাষায়, এটি আইইইই 754 মানের উপর ভিত্তি করে । সমস্যার সরলতাটি হ'ল সংখ্যাগুলি এই বিন্যাসে প্রতিনিধিত্ব করা হয় পুরো দুটি বারের শক্তির হিসাবে; যৌক্তিক সংখ্যা (যেমন 0.1
, যা 1/10
) যার ডিনোমিনেটর দু'জনের শক্তি নয় সঠিকভাবে উপস্থাপন করা যায় না।
জন্য 0.1
মান মধ্যে binary64
ফরম্যাট, উপস্থাপনা ঠিক হিসেবে লেখা যেতে পারে
0.1000000000000000055511151231257827021181583404541015625
দশমিক মধ্যে, বা0x1.999999999999ap-4
মধ্যে C99 hexfloat স্বরলিপি ।বিপরীতে, যুক্তিযুক্ত সংখ্যা 0.1
, যা হয় 1/10
ঠিক ঠিক হিসাবে লেখা যেতে পারে
0.1
দশমিক মধ্যে, বা0x1.99999999999999...p-4
সি 99 হেক্সফ্লায়েট স্বরলিপিটির একটি অ্যানালগে, যেখানে ...
9 এর সমাপ্তি ধারাবাহিকতা উপস্থাপন করে।আপনার প্রোগ্রামে ধ্রুবকগুলি 0.2
এবং 0.3
তাদের প্রকৃত মূল্যবোধগুলির সাথে অনুমানও হবে। ঘটনাচক্রে নিকটস্থ যে double
করতে 0.2
মূলদ সংখ্যার চেয়ে বড় 0.2
কিন্তু যে নিকটতম double
করতে 0.3
মূলদ সংখ্যার চেয়ে কম 0.3
। যোগফল 0.1
এবং 0.2
যুক্তিযুক্ত সংখ্যার চেয়ে বড় হয়ে বাড়ে 0.3
এবং তাই আপনার কোডের ধ্রুবকটির সাথে একমত নন।
ভাসমান-পয়েন্ট পাটিগণিত বিষয়গুলির একটি মোটামুটি বিস্তৃত চিকিত্সা হ'ল প্রতিটি কম্পিউটার বিজ্ঞানী ভাসমান-পয়েন্ট পাটিগণিত সম্পর্কে জানা উচিত । সহজে-ডাইজেস্ট ব্যাখ্যার জন্য ভাসমান -পয়েন্ট- gui.de দেখুন ।
পার্শ্ব দ্রষ্টব্য: সমস্ত অবস্থানগত (বেস-এন) নম্বর সিস্টেম নির্ভুলতার সাথে এই সমস্যাটি ভাগ করে
সরল পুরাতন দশমিক (বেস 10) সংখ্যার একই সমস্যা রয়েছে, এ কারণেই 1/3 এর মতো নম্বরগুলি 0.333333333 হিসাবে শেষ হয় ...
আপনি কেবলমাত্র একটি সংখ্যায় (3-10) হোঁচট খেয়েছেন যা দশমিক সিস্টেমের সাথে প্রতিনিধিত্ব করা সহজ বলে মনে হয় তবে বাইনারি সিস্টেমে ফিট করে না। এটি উভয় উপায়েও যায় (কিছুটা কম ডিগ্রীতেও): ১/১16 দশমিক (০.০6২৫) এ একটি কুৎসিত সংখ্যা, তবে বাইনারিতে এটি দশম (১০,০০০) **-তে যতটা 10,000 এর মতো পরিষ্কার ঝরঝরে দেখাচ্ছে - যদি আমরা থাকতাম আমাদের প্রতিদিনের জীবনে বেস -২ নম্বর সিস্টেমটি ব্যবহার করার অভ্যাসটি, আপনি এমনকি সেই সংখ্যাটি দেখতে চাইবেন এবং স্বভাবতই বুঝতে পারবেন যে আপনি সেখানে কিছুটা অর্ধেক রেখে আবার পৌঁছে যেতে পারেন এবং বারবার ফিরে আসতে পারেন।
** অবশ্যই, ভাসমান-পয়েন্ট সংখ্যাগুলি মেমরিতে কীভাবে সংরক্ষণ করা হয় তা নয় (তারা বৈজ্ঞানিক স্বরলিপি ব্যবহার করে)। তবে এটি সেই বিন্দুর চিত্র তুলে ধরেছে যে বাইনারি ভাসমান-পয়েন্ট যথার্থ ত্রুটিগুলি ক্রপ হওয়ার প্রবণতা দেখা দেয় কারণ আমরা যে "আসল ওয়ার্ল্ড" নাম্বারগুলির সাথে সাধারণত কাজ করতে আগ্রহী তা প্রায় দশবারের শক্তি - তবে কেবলমাত্র আমরা দশমিক সংখ্যা সিস্টেমের দিন ব্যবহার করি- আজ. এ কারণেই আমরা "প্রতি of জনের মধ্যে ৫" এর পরিবর্তে %১% এর মতো জিনিসগুলি বলব (%১% একটি অনুমান, কারণ ৫/ any কোনও দশমিক সংখ্যার সাথে হুবহু উপস্থাপন করা যায় না)।
সুতরাং না: বাইনারি ভাসমান পয়েন্ট সংখ্যাগুলি ভাঙা হয় না, তারা কেবল প্রতিটি অন্যান্য বেস-এন নম্বর সিস্টেমের মতো অপূর্ণ হতে পারে :)
সাইড সাইড নোট: প্রোগ্রামিং ইন ফ্লোটের সাথে কাজ করা
অনুশীলনে, নির্ভুলতার এই সমস্যাটির অর্থ হল আপনার ভাসমান পয়েন্ট সংখ্যাগুলিকে গোল করার জন্য আপনাকে যতগুলি দশমিক জায়গাগুলি আগ্রহী সেগুলি প্রদর্শন করার আগে আপনি গোল করে ফাংশনগুলি ব্যবহার করতে হবে।
আপনাকে সাম্যতা পরীক্ষাগুলি তুলনা করে প্রতিস্থাপন করতে হবে যা কিছু পরিমাণ সহনশীলতার মঞ্জুরি দেয়, যার অর্থ:
না না নাif (x == y) { ... }
পরিবর্তে না if (abs(x - y) < myToleranceValue) { ... }
।
abs
পরম মান যেখানে । myToleranceValue
আপনার নির্দিষ্ট অ্যাপ্লিকেশনটির জন্য বেছে নেওয়া দরকার - এবং আপনি কতটা "উইগল রুম" অনুমতি দেওয়ার জন্য প্রস্তুত তা নিয়ে অনেক কিছু থাকবে এবং আপনি যে বৃহত্তম সংখ্যার সাথে তুলনা করতে যাচ্ছেন তা হতে পারে (নির্ভুলতার সমস্যাগুলির কারণে) )। আপনার পছন্দের ভাষাতে "এপসিলন" স্টাইলের ধ্রুবক সম্পর্কে সাবধান থাকুন। এগুলি সহনশীলতার মান হিসাবে ব্যবহৃত হবে না ।
আমি বিশ্বাস করি যেহেতু আমি ভাসমান পয়েন্ট হার্ডওয়্যার ডিজাইন করি এবং তৈরি করি সেহেতু আমার এটিতে একটি হার্ডওয়্যার ডিজাইনারের দৃষ্টিভঙ্গি যুক্ত করা উচিত। ত্রুটিটির উত্স জানার ফলে সফ্টওয়্যারটিতে কী ঘটছে তা বুঝতে সহায়তা করতে পারে এবং শেষ পর্যন্ত, আমি আশা করি যে এটি কেন ভাসমান পয়েন্ট ত্রুটিগুলি ঘটে যায় এবং সময়ের সাথে এটি কীভাবে জমা হয় বলে মনে হয় তার কারণগুলি ব্যাখ্যা করতে সহায়তা করে।
ইঞ্জিনিয়ারিং দৃষ্টিকোণ থেকে, বেশিরভাগ ফ্লোটিং পয়েন্ট অপারেশনগুলির ত্রুটির কিছু উপাদান থাকবে কারণ যে হার্ডওয়্যারটি যে ফ্লোটিং পয়েন্ট গণনা করে কেবল শেষ স্থানে এক ইউনিটের অর্ধেকেরও কম ত্রুটি থাকা প্রয়োজন। অতএব, অনেক হার্ডওয়্যার একটি নির্ভুলতায় থামবে যা কেবলমাত্র এক ইউনিটের অর্ধেকেরও কম ত্রুটি উত্পন্ন করার জন্য একটি একক ক্রিয়াকলাপের জন্য যা বিশেষত ভাসমান পয়েন্ট বিভাগে সমস্যাযুক্ত। একক ক্রিয়াকলাপটি কী গঠন করে তা ইউনিট কত অপারেট নেয় তার উপর নির্ভর করে। বেশিরভাগ ক্ষেত্রে এটি দুটি, তবে কিছু ইউনিট 3 বা ততোধিক সংখ্যক অপারেন্ড নেয়। এর কারণে, সময়ের সাথে সাথে ত্রুটিগুলি যুক্ত হওয়ার কারণে বারবার অপারেশনগুলি একটি কাঙ্ক্ষিত ত্রুটি ঘটবে এমন কোনও গ্যারান্টি নেই।
বেশিরভাগ প্রসেসর আইইইই -754 অনুসরণ করে -754 স্ট্যান্ডার্ড তবে কিছু ডেনারমালাইজড বা বিভিন্ন স্ট্যান্ডার্ড ব্যবহার করে। উদাহরণস্বরূপ, আইইইই -754 এ একটি ডেনারমালাইজড মোড রয়েছে যা নির্ভুলতার ব্যয়ে খুব ছোট ভাসমান পয়েন্ট সংখ্যা উপস্থাপনের অনুমতি দেয়। নিম্নলিখিত, তবে, আইইইই -754 এর স্বাভাবিকীকরণ মোডটি কভার করবে যা অপারেশনটির সাধারণ মোড।
আইইইই-754৪ স্ট্যান্ডার্ডে, হার্ডওয়্যার ডিজাইনারদের ত্রুটি / এপসিলনের কোনও মান অনুমোদিত হয় যতক্ষণ না এটি শেষ স্থানে এক ইউনিটের অর্ধেকেরও কম, এবং ফলাফলটি কেবল সর্বশেষে এক ইউনিটের অর্ধেকেরও কম হতে হবে একটি অপারেশন জন্য স্থান। এটি ব্যাখ্যা করে যে কেন যখন বারবার অপারেশন করা হয়, ত্রুটিগুলি যুক্ত হয়। আইইইই-75 75৪ ডাবল স্পষ্টতার জন্য, এটি 54 তম বিট, যেহেতু 53 বিটগুলি ভাসমান পয়েন্ট সংখ্যার (যেমন, ম্যান্টিসা) নামক সংখ্যাটি (সাধারণকরণ) উপস্থাপন করতে ব্যবহৃত হয় (উদাহরণস্বরূপ 5.3e5-তে 5.3)। পরবর্তী বিভাগগুলি বিভিন্ন ভাসমান পয়েন্ট ক্রিয়াকলাপগুলিতে হার্ডওয়্যার ত্রুটির কারণগুলি সম্পর্কে আরও বিশদে যায়।
ভাসমান বিন্দু বিভাগে ত্রুটির মূল কারণটি ভাগফল গণনা করার জন্য ব্যবহৃত বিভাগ অ্যালগরিদম। সর্বাধিক কম্পিউটার সিস্টেম, একটি বিপরীত দ্বারা গুণ ব্যবহার বিভাজন নিরূপণ প্রধানত মধ্যে Z=X/Y
,Z = X * (1/Y)
। একটি বিভাগ পুনরাবৃত্তভাবে গণনা করা হয় অর্থাত্ প্রতিটি চক্রটি যথাক্রমে নির্ভুলতা না পাওয়া পর্যন্ত ভাগফলের কিছু বিট গণনা করে, যা আইইইই -754 এর জন্য শেষ স্থানে এক ইউনিটেরও কম ত্রুটিযুক্ত এমন কোনও কিছুই। Y (1 / Y) এর পুনঃপ্রেরণের টেবিলটি ধীর বিভাগে ভাগফল নির্বাচন টেবিল (কিউএসটি) হিসাবে পরিচিত, এবং ভাগফল নির্বাচন টেবিলের বিটগুলির আকারটি সাধারণত রেডিক্সের প্রস্থ বা বেশ কয়েকটি বিট হয় ভাগফল প্রতিটি পুনরাবৃত্তিতে গুণিত হয়, এবং কয়েক গার্ড বিট। আইইইই-754৪ স্ট্যান্ডার্ড, ডাবল যথার্থতা (64৪-বিট) এর জন্য এটি ডিভাইডারের মূলাকৃতির আকার এবং কয়েকটি গার্ড বিট কে হবে যেখানেk>=2
। সুতরাং উদাহরণস্বরূপ, একটি বিভাজকের জন্য একটি আদর্শ কোটিয়েন্টিয়েন্ট সিলেকশন টেবিল যা একসাথে ভাগফলের 2 বিট গণনা করে (মূলা 4) 2+2= 4
বিট (আরও কয়েকটি aচ্ছিক বিট) হবে।
৩.১ বিভাগের রাউন্ডিং ত্রুটি: পারিশ্রমিকের সমাপ্তি
ভাগফল নির্বাচনের টেবিলে কী পারস্পরিক ফলাফল রয়েছে তা বিভাগের পদ্ধতির উপর নির্ভর করে : এসআরটি বিভাগের মতো ধীর বিভাজন, বা স্বল্প বিভাগ যেমন গোল্ডস্কমিট বিভাগ; প্রতিটি এন্ট্রি সর্বনিম্ন সম্ভাব্য ত্রুটি অর্জনের প্রয়াসে বিভাগ অ্যালগরিদম অনুযায়ী সংশোধিত হয়। যাইহোক যাইহোক, সমস্ত পারস্পরিক প্রতিদানগুলি আনুমানিক areপ্রকৃত পরস্পর সম্পর্কিত এবং ত্রুটির কিছু উপাদান পরিচয় করিয়ে দিন। ধীর বিভাজন এবং দ্রুত বিভাগ উভয় পদ্ধতিই ভাগফলকে পুনরাবৃত্তভাবে গণনা করে, অর্থাত অংশের কয়েকটি বিট কয়েকটি ধাপে গণনা করা হয়, তারপরে ফলাফলটি লভ্যাংশ থেকে বিয়োগ করা হয় এবং ত্রুটি একের অর্ধেকেরও কম না হওয়া পর্যন্ত বিভাজক পদক্ষেপগুলি পুনরাবৃত্তি করে শেষ স্থানে ইউনিট ধীর বিভাজন পদ্ধতিগুলি প্রতিটি পদক্ষেপে ভাগফলের একটি নির্দিষ্ট সংখ্যার অঙ্ক গণনা করে এবং এটি নির্মাণে সাধারণত কম ব্যয়বহুল এবং দ্রুত বিভাগের পদ্ধতিগুলি প্রতি পদক্ষেপে পরিবর্তনশীল সংখ্যার গণনা করে এবং সাধারণত এটি নির্মাণে আরও ব্যয়বহুল হয়। বিভাগ পদ্ধতিগুলির সর্বাধিক গুরুত্বপূর্ণ অংশটি হ'ল তাদের বেশিরভাগই পুনরাবৃত্তির কাছাকাছি সময়ে পুনরাবৃত্ত গুণনের উপর নির্ভর করে , তাই তারা ত্রুটির প্রবণ হয়।
সমস্ত ক্রিয়াকলাপে রাউন্ডিং ত্রুটিগুলির আরেকটি কারণ হ'ল আইইইই -৫ 75৪ মঞ্জুরি দেয় এমন চূড়ান্ত উত্তরের কাণ্ডের বিভিন্ন পদ্ধতি। এখানে কাটা, গোল-দিকের-শূন্য, রাউন্ড-টু-নিকটস্থ (ডিফল্ট), রাউন্ড-ডাউন এবং রাউন্ড-আপ রয়েছে। সমস্ত পদ্ধতি একক ক্রিয়াকলাপের জন্য শেষ স্থানে এক ইউনিটেরও কম ত্রুটির একটি উপাদান পরিচয় করিয়ে দেয়। সময় এবং পুনরাবৃত্তি ক্রিয়াকলাপগুলির পরে, কাটাও ত্রুটির সাথে সংশ্লেষ যোগ করে। এই কাটা ত্রুটিটি বিশেষত ক্ষতিকারক ক্ষেত্রে সমস্যাযুক্ত, যার মধ্যে কিছুটা পুনরাবৃত্তি গুণ করা যায়।
যেহেতু হার্ডওয়্যারটি ভাসমান পয়েন্ট গণনা করে কেবল কোনও একক ক্রিয়াকলাপের জন্য শেষ স্থানে এক ইউনিটের অর্ধেকেরও কম ত্রুটির সাথে একটি ফলাফল অর্জন করতে পারে, তাই যদি ত্রুটি না দেখা যায় তবে পুনরাবৃত্ত ক্রিয়াকলাপগুলিতে ত্রুটি বৃদ্ধি পাবে। এই কারণটিই যে গণনাগুলিতে একটি গণ্ডিযুক্ত ত্রুটির প্রয়োজন হয়, গণিতবিদরা আইইইই -754 এর শেষ স্থানে রাউন্ড টু-নিকটতম এমনকি অঙ্কটি ব্যবহার করার মতো পদ্ধতি ব্যবহার করেন কারণ সময়ের সাথে সাথে ত্রুটিগুলি একে অপরকে বাতিল করার সম্ভাবনা বেশি থাকে আউট, এবং ব্যবধান পাটিগণিত এর বৈচিত্র সঙ্গে মিলিত আইইইই 754 rounding মোডবৃত্তাকার ত্রুটিগুলির পূর্বাভাস দিতে এবং সেগুলি সংশোধন করতে। অন্যান্য রাউন্ডিং মোডের তুলনায় এর নিম্ন আপেক্ষিক ত্রুটির কারণে, নিকটতম এমনকি অঙ্কের (শেষ স্থানে) গোলাকার, আইইইই -754 এর ডিফল্ট রাউন্ডিং মোড।
নোট করুন যে ডিফল্ট রাউন্ডিং মোড, শেষ স্থানে রাউন্ড-টু-নিকটতম এমনকি অঙ্ক , এক ক্রিয়াকলাপের জন্য শেষ স্থানে এক ইউনিটের অর্ধেকেরও কম ত্রুটির গ্যারান্টি দেয়। কাটা কাটা, রাউন্ড-আপ এবং একা রাউন্ড ডাউন ব্যবহারের ফলে এমন একটি ত্রুটি হতে পারে যা শেষ স্থানে এক ইউনিটের অর্ধেকের বেশি, তবে শেষ স্থানে এক ইউনিটেরও কম থাকে, সুতরাং এই মোডগুলি না করা ছাড়া প্রস্তাব দেওয়া হয় না ব্যবধানে গাণিতিক ব্যবহৃত।
সংক্ষেপে, ভাসমান পয়েন্ট ক্রিয়াকলাপগুলির ত্রুটির মূল কারণ হ'ল হার্ডওয়্যারে কাটা কাটা এবং বিভাজনের ক্ষেত্রে পরস্পর বিচ্ছিন্নকরণের সংমিশ্রণ। যেহেতু আইইইই-75 75৪ স্ট্যান্ডার্ডটি কেবলমাত্র একক ক্রিয়াকলাপের জন্য শেষ স্থানে এক ইউনিটের অর্ধেকেরও কম ত্রুটির প্রয়োজন, তাই সংশোধন না করা হলে পুনরাবৃত্ত ক্রিয়াকলাপগুলির উপর ভাসমান পয়েন্ট ত্রুটিগুলি যুক্ত হবে।
যখন আপনি .1 বা 1/10 কে বেস 2 (বাইনারি) এ রূপান্তর করেন আপনি দশমিক পয়েন্টের পরে পুনরাবৃত্তি প্যাটার্নটি পান, ঠিক যেমন বেস 10 তে 1/3 উপস্থাপন করার চেষ্টা করার মতো মান সঠিক নয়, এবং তাই আপনি করতে পারবেন না সাধারণ ভাসমান পয়েন্ট পদ্ধতি ব্যবহার করে এর সাথে সঠিক গণিত।
এখানে বেশিরভাগ উত্তর খুব শুষ্ক, প্রযুক্তিগত দিক দিয়ে এই প্রশ্নের সমাধান করে। আমি এটিকে এমন পদে সম্বোধন করতে চাই যা সাধারণ মানুষ বুঝতে পারে।
কল্পনা করুন যে আপনি পিজ্জা টুকরো টুকরো করার চেষ্টা করছেন। আপনি একটি রোবটিক পিজা কর্তনকারী যে পিজা টুকরা কাটা পারেন ঠিক অর্ধেক। এটি পুরো পিজ্জা অর্ধেক করতে পারে, বা এটি কোনও বিদ্যমান স্লাইস অর্ধেক করতে পারে, তবে যে কোনও ক্ষেত্রে, অর্ধেকটি সর্বদা সঠিক।
এই পিৎজা কাটারটির খুব সূক্ষ্ম গতিবিধি রয়েছে এবং আপনি যদি পুরো পিজ্জা দিয়ে শুরু করেন তবে তা অর্ধেক করে নিন এবং প্রতিবার ক্ষুদ্রতম টুকরোটি অর্ধেক চালিয়ে যেতে পারেন, এমনকি উচ্চতর নির্ভুলতার ক্ষমতাগুলির জন্য স্লাইস খুব ছোট হওয়ার আগে আপনি 53 বার অর্ধেকটি করতে পারেন । এই মুহুর্তে, আপনি যে খুব পাতলা স্লাইসটি আর অর্ধেক রাখতে পারবেন না, তবে এটি অবশ্যই অন্তর্ভুক্ত বা বাদ দেওয়া উচিত।
এখন, আপনি কীভাবে এমন সমস্ত টুকরো টুকরো টুকরো করবেন যা পিজ্জার দশমাংশ (0.1) বা পঞ্চমাংশ (0.2) পর্যন্ত যোগ করবে? সত্যিই এটি সম্পর্কে চিন্তা করুন, এবং এটি চেষ্টা করে দেখুন। এমনকি যদি আপনার কাছে কোনও পৌরাণিক নির্ভুল পিজ্জা কাটার থাকে তবে আপনি একটি বাস্তব পিজ্জা ব্যবহার করার চেষ্টা করতে পারেন। :-)
সর্বাধিক অভিজ্ঞ প্রোগ্রামারদের, অবশ্যই, বাস্তব উত্তর, যা একসঙ্গে টুকরা করার কোনো উপায় একটি নেই জানি সঠিক দশম বা পিত্জার পঞ্চম ঐ টুকরা ব্যবহার করে, কোন ব্যাপার কিভাবে finely, আপনি তাদের যেভাবেই। আপনি একটি খুব ভাল আনুমানিকতা করতে পারেন, এবং আপনি যদি ০.০ এর সমমানের সাথে ০. এর কাছাকাছি যোগ করেন তবে আপনি ০.০ এর একটি খুব ভাল অনুমান পেতে পারেন, তবে এটি এখনও ঠিক এটিই, একটি প্রায় অনুমান।
ডাবল-স্পষ্টতা সংখ্যার জন্য (যা নির্ভুলতা আপনাকে আপনার পিজ্জা 53 বার অর্ধেক করার অনুমতি দেয়) জন্য, তাত্ক্ষণিক কম এবং 0.1 এর চেয়ে বেশি নম্বরগুলি 0.09999999999999999167332731531132594682276248931884765625 এবং 0.1000000000000555111512312578270211815834045410। পূর্ববর্তীটি পূর্বের তুলনায় বেশ কিছুটা 0.1 এর কাছাকাছি, সুতরাং একটি সংখ্যার পার্সার, 0.1 এর একটি ইনপুট দেওয়া, পরবর্তীটির পক্ষে হবে favor
(এই দুটি সংখ্যার মধ্যে পার্থক্য হ'ল "ক্ষুদ্রতম স্লাইস" যা আমাদের অবশ্যই অন্তর্ভুক্ত করার সিদ্ধান্ত নিতে হবে, যা একটি wardর্ধ্বমুখী পক্ষপাতের পরিচয় দেয়, বা বাদ দেয়, যা নিম্নমুখী পক্ষপাতের পরিচয় দেয় that সেই ক্ষুদ্রতম স্লাইসের জন্য প্রযুক্তিগত শব্দটি একটি lpাল হয় ))
০.২ এর ক্ষেত্রে, সংখ্যাগুলি সমস্ত একই, কেবল ২ এর গুণক দ্বারা ছোট করে দেওয়া হয়েছে আবারও, আমরা সেই মানটির পক্ষে যা 0.2 এর তুলনায় কিছুটা বেশি।
লক্ষ করুন যে উভয় ক্ষেত্রেই ০.০ এবং ০.২ এর জন্য অনুমানের ক্ষেত্রে সামান্য upর্ধ্বমুখী পক্ষপাত রয়েছে। যদি আমরা এই পক্ষপাতদুষ্টাগুলির মধ্যে যথেষ্ট পরিমাণ যুক্ত করি তবে তারা সংখ্যাটি আমাদের যা চায় তার থেকে আরও দূরে ঠেলে দেবে, এবং প্রকৃতপক্ষে ০.০ + ০.২ এর ক্ষেত্রে পক্ষপাতটি এত বেশি যে ফলস্বরূপ সংখ্যাটি এখন নিকটতম সংখ্যা নয় থেকে 0.3।
বিশেষত, 0.1 + 0.2 সত্যিই 0.1000000000000000035511151231257827021181583404541015625 + 0.200000000000000000000000000110000000000000000000000000000000000008203125 এর কেইউয়াস্তে জবাবদিস্তি হয়েছে 9880082098008208008208008208008208008208008208008208008008008208008208008008208008008008008008008208008208008008008008008208008008208008008208008,815980000
পিএস কিছু প্রোগ্রামিং ল্যাঙ্গুয়েজ পিজ্জা কাটার সরবরাহ করে যা স্লাইসগুলি সঠিক দশমীতে বিভক্ত করতে পারে । যদিও এই জাতীয় পিৎজার কাটারগুলি অসাধারণ, যদি আপনার কোনওটিতে অ্যাক্সেস থাকে তবে আপনার অবশ্যই এটি ব্যবহার করা উচিত যখন এক স্লাইসের এক-দশমাংশ বা এক-পঞ্চমাংশ ঠিক পাওয়া সম্ভব important
ভাসমান পয়েন্ট রাউন্ডিং ত্রুটি। ৫. এর অনুপস্থিত মৌলিক গুণকের কারণে বেস -১ তে যেমন বেস -২ তে ০.১ যথাযথভাবে উপস্থাপিত হতে পারে না ঠিক যেমন ১/৩ দশমিক হিসাবে প্রতিনিধিত্ব করতে অসীম সংখ্যার গ্রহণ করে তবে বেস -৩-তে "০.০", ০.০ বেস -২ এ অসীম সংখ্যার সংখ্যা নেয় যেখানে এটি বেস -10 এ নয়। এবং কম্পিউটারগুলির অসীম পরিমাণে স্মৃতি থাকে না।
অন্যান্য সঠিক উত্তর ছাড়াও, আপনি ভাসমান-পয়েন্ট পাটিগণিত নিয়ে সমস্যা এড়াতে আপনার মানগুলি স্কেলিং বিবেচনা করতে পারেন।
উদাহরণ স্বরূপ:
var result = 1.0 + 2.0; // result === 3.0 returns true
... পরিবর্তে:
var result = 0.1 + 0.2; // result === 0.3 returns false
জাভাস্ক্রিপ্টে অভিব্যক্তিটি 0.1 + 0.2 === 0.3
ফিরে আসে false
, তবে ভাগ্যক্রমে ভাসমান-বিন্দুতে পূর্ণসংখ্যার গাণিতিকটি সঠিক, সুতরাং দশমিক উপস্থাপনের ত্রুটিগুলি স্কেলিং দ্বারা এড়ানো যায়।
ব্যবহারিক উদাহরণ হিসাবে, ভাসমান-পয়েন্ট সমস্যাগুলি এড়ানোর জন্য যেখানে নির্ভুলতা সর্বমোট হয়, ডলারের পরিবর্তে সেন্টের সংখ্যা: সেন্টের প্রতিনিধিত্ব করে একটি পূর্ণসংখ্যা হিসাবে অর্থ পরিচালনার জন্য 1 টি সুপারিশ করা হয় ।2550
25.50
1 ডগলাস ক্রকফোর্ড: জাভাস্ক্রিপ্ট: ভাল পার্টস : পরিশিষ্ট এ - ভয়ঙ্কর যন্ত্রাংশ (পৃষ্ঠা 105) ।
আমার উত্তরটি বেশ দীর্ঘ, সুতরাং আমি এটিকে তিনটি ভাগে ভাগ করেছি। যেহেতু প্রশ্নটি ভাসমান পয়েন্ট গণিত সম্পর্কে, তাই আমি মেশিনটি আসলে কী করে তার উপর জোর দিয়েছি। আমি এটিকে দ্বিগুণ (bit৪ বিট) নির্ভুলতার জন্যও নির্দিষ্ট করে দিয়েছি তবে যুক্তিটি কোনও ভাসমান বিন্দুতে সমানভাবে প্রযোজ্য।
প্রস্তাবনা
একটি আইইইই 754 ডাবল-স্পষ্টতা বাইনারি ফ্লোটিং-পয়েন্ট ফর্ম্যাট (বাইনারি 64) নম্বরটি ফর্মের একটি সংখ্যা উপস্থাপন করে
মান = (-1) * s * (1. মি 51 মি 50 ... মি 2 মি 1 মি 0 ) 2 * 2 ই -1023
64 বিট মধ্যে:
1
যদি সংখ্যাটি নেতিবাচক হয়, 0
অন্যথায় 1 ।1.
সর্বদা 2 বাদ দেওয়া হয় যেহেতু যে কোনও বাইনারি মানের সবচেয়ে উল্লেখযোগ্য বিট হয় 1
।1 - আইইইই 754 স্বাক্ষরিত শূন্যের ধারণার জন্য অনুমতি দেয় - +0
এবং -0
আলাদাভাবে চিকিত্সা করা হয়: 1 / (+0)
এটি ইতিবাচক অনন্ত; 1 / (-0)
নেতিবাচক অনন্ত। শূন্য মানগুলির জন্য, ম্যান্টিসা এবং এক্সপোনেন্ট বিটগুলি সমস্ত শূন্য। দ্রষ্টব্য: শূন্য মানগুলি (+0 এবং -0) স্পষ্টতই ডেনারমাল 2 হিসাবে শ্রেণিবদ্ধ নয় ।
2 - এটি ডেনরমাল সংখ্যার ক্ষেত্রে নয় , যার শূন্যের অফসেট এক্সপোঞ্জেন (এবং একটি অন্তর্নিহিত 0.
) রয়েছে। ডেনরমাল ডাবল যথার্থ সংখ্যার পরিসীমা ডি মিনিট ≤ | x | Max ডি সর্বাধিক , যেখানে ডি মিনিট (ক্ষুদ্রতম প্রতিনিধিত্বযোগ্য ননজারো সংখ্যা) 2 -1023 - 51 (≈ 4.94 * 10 -324 ) এবং ডি সর্বাধিক (বৃহত্তম সংখ্যাসূচক সংখ্যা, যার জন্য মান্টিস সম্পূর্ণরূপে 1
গুলি) 2 -1023 + 1 - 2 -1023 - 51 (≈ 2.225 * 10 -308 )।
দ্বৈত নির্ভুল সংখ্যাটি বাইনারি রূপান্তর করা
দ্বৈত নির্ভুলতা ভাসমান পয়েন্ট সংখ্যাটিকে বাইনারি রূপান্তর করতে অনেক অনলাইন রূপান্তরকারীর উপস্থিতি রয়েছে (যেমন বাইনারি কনভার্ট ডট কম ), তবে ডাবল নির্ভুলতার সংখ্যার জন্য আইইইই 754 উপস্থাপনা পাওয়ার জন্য এখানে কিছু নমুনা সি # কোড দেওয়া হয়েছে (আমি তিনটি অংশ কলোন দিয়ে পৃথক করি :
) :
public static string BinaryRepresentation(double value)
{
long valueInLongType = BitConverter.DoubleToInt64Bits(value);
string bits = Convert.ToString(valueInLongType, 2);
string leadingZeros = new string('0', 64 - bits.Length);
string binaryRepresentation = leadingZeros + bits;
string sign = binaryRepresentation[0].ToString();
string exponent = binaryRepresentation.Substring(1, 11);
string mantissa = binaryRepresentation.Substring(12);
return string.Format("{0}:{1}:{2}", sign, exponent, mantissa);
}
মূল বক্তব্য: পৌঁছনো
(টিএল; ডিআর সংস্করণের জন্য নীচে যান)
ক্যাটো জনস্টন (প্রশ্নকারী) জিজ্ঞাসা করলেন কেন 0.1 + 0.2! = 0.3।
বাইনারিতে লিখিত (তিনটি অংশ পৃথককারী কলোন সহ), আইইইইই 754 মানগুলির উপস্থাপনা হ'ল:
0.1 => 0:01111111011:1001100110011001100110011001100110011001100110011010
0.2 => 0:01111111100:1001100110011001100110011001100110011001100110011010
নোট করুন যে ম্যান্টিসাটি পুনরাবৃত্ত সংখ্যাগুলির সমন্বয়ে গঠিত 0011
। গণনার ক্ষেত্রে কেন ত্রুটি রয়েছে তার মূল কারণ - 0.1, 0.2 এবং 0.3 বাইনারিগুলিতে সুনির্দিষ্টভাবে বাইনারি বিটের একটি নির্দিষ্ট সংখ্যায় 1/9, 1/3 বা 1/7 এর চেয়ে বেশি প্রতিনিধিত্ব করা যেতে পারে দশমিক সংখ্যা ।
এছাড়াও নোট করুন যে আমরা ঘনিষ্ঠতায় পাওয়ারটি 52 দ্বারা হ্রাস করতে পারি এবং বাইনারি উপস্থাপনার পয়েন্টটি 52 টি জায়গায় ডানদিকে স্থানান্তর করতে পারি (অনেকটা 10 -3 * 1.23 == 10 -5 * 123)। এটি তখন বাইনারি উপস্থাপনাকে সঠিক মান হিসাবে উপস্থাপন করতে সক্ষম করে যা এটি একটি * 2 পি আকারে প্রতিনিধিত্ব করে । যেখানে 'ক' একটি পূর্ণসংখ্যা।
এক্সটেনশনগুলিকে দশমিক রূপান্তর করা, অফসেটটি সরিয়ে, এবং উল্লিখিত 1
(বর্গাকার বন্ধনীগুলিতে), 0.1 এবং 0.2 পুনরায় যুক্ত করা হয়:
0.1 => 2^-4 * [1].1001100110011001100110011001100110011001100110011010
0.2 => 2^-3 * [1].1001100110011001100110011001100110011001100110011010
or
0.1 => 2^-56 * 7205759403792794 = 0.1000000000000000055511151231257827021181583404541015625
0.2 => 2^-55 * 7205759403792794 = 0.200000000000000011102230246251565404236316680908203125
দুটি সংখ্যার যোগ করতে এক্সপোশনটি একই হওয়া দরকার, অর্থাত:
0.1 => 2^-3 * 0.1100110011001100110011001100110011001100110011001101(0)
0.2 => 2^-3 * 1.1001100110011001100110011001100110011001100110011010
sum = 2^-3 * 10.0110011001100110011001100110011001100110011001100111
or
0.1 => 2^-55 * 3602879701896397 = 0.1000000000000000055511151231257827021181583404541015625
0.2 => 2^-55 * 7205759403792794 = 0.200000000000000011102230246251565404236316680908203125
sum = 2^-55 * 10808639105689191 = 0.3000000000000000166533453693773481063544750213623046875
যেহেতু সমষ্টি ফর্ম 2 নয় এন * 1. {BBB} আমরা একের পর সূচক বৃদ্ধি এবং দশমিক (নামান বাইনারি ) পয়েন্ট পেতে হবে:
sum = 2^-2 * 1.0011001100110011001100110011001100110011001100110011(1)
= 2^-54 * 5404319552844595.5 = 0.3000000000000000166533453693773481063544750213623046875
মান্টিসায় এখন 53 টি বিট রয়েছে (53 তম উপরের লাইনে বর্গাকার বন্ধনীতে রয়েছে)। ডিফল্ট rounding মোড আইইইই 754 জন্য ' নিকটবর্তী গোল ' - অর্থাত একটি সংখ্যা যদি এক্স দুটি মানের মধ্যে বৃক্ষের পতন একটি এবং খ , মান যেখানে অন্তত গুরুত্বপূর্ণ বিট শূন্য নির্বাচিত করা হয়।
a = 2^-54 * 5404319552844595 = 0.299999999999999988897769753748434595763683319091796875
= 2^-2 * 1.0011001100110011001100110011001100110011001100110011
x = 2^-2 * 1.0011001100110011001100110011001100110011001100110011(1)
b = 2^-2 * 1.0011001100110011001100110011001100110011001100110100
= 2^-54 * 5404319552844596 = 0.3000000000000000444089209850062616169452667236328125
নোট করুন যে ক এবং খ শুধুমাত্র শেষ বিট মধ্যে পৃথক; ...0011
+ 1
= ...0100
। এই ক্ষেত্রে শূন্যের সর্বনিম্ন উল্লেখযোগ্য বিটের মানটি খ , সুতরাং যোগফলটি হ'ল:
sum = 2^-2 * 1.0011001100110011001100110011001100110011001100110100
= 2^-54 * 5404319552844596 = 0.3000000000000000444089209850062616169452667236328125
যদিও ০.০ এর বাইনারি উপস্থাপনাটি হ'ল:
0.3 => 2^-2 * 1.0011001100110011001100110011001100110011001100110011
= 2^-54 * 5404319552844595 = 0.299999999999999988897769753748434595763683319091796875
যা শুধুমাত্র 2 দ্বারা 0.1 থেকে 0.2 এর সমষ্টি বাইনারি উপস্থাপনা থেকে পৃথক -54 ।
০.১ এবং ০.২ এর বাইনারি উপস্থাপনা হ'ল আইইইই 754 দ্বারা অনুমোদিত নম্বরের সর্বাধিক নির্ভুল প্রতিনিধিত্ব।
টি এল; ডিআর
লেখা 0.1 + 0.2
একটি আইইইই 754 বাইনারি প্রতিনিধিত্ব (তিনটি অংশ আলাদা কোলন সহ) এবং তুলনা 0.3
(আমি বর্গাকার বন্ধনী মধ্যে স্বতন্ত্র বিট রেখেছি) এই হল:
0.1 + 0.2 => 0:01111111101:0011001100110011001100110011001100110011001100110[100]
0.3 => 0:01111111101:0011001100110011001100110011001100110011001100110[011]
দশমীতে ফিরে রূপান্তরিত, এই মানগুলি হ'ল:
0.1 + 0.2 => 0.300000000000000044408920985006...
0.3 => 0.299999999999999988897769753748...
পার্থক্যটি হুবহু 2 -54 , যা মূল মানগুলির সাথে তুলনা করলে তুচ্ছ (অনেক অ্যাপ্লিকেশনের জন্য) - 5.5511151231258 × 10 -17 ।
ভাসমান পয়েন্ট সংখ্যার শেষ কয়েকটি বিটের তুলনা করা সহজাতভাবে বিপজ্জনক, কারণ বিখ্যাত " ফ্লোটিং-পয়েন্ট অ্যারিমেটিক সম্পর্কে প্রতিটি কম্পিউটার বিজ্ঞানী কি জানা উচিত " পড়েন তিনি জানেন (যা এই উত্তরের সমস্ত প্রধান অংশকে কভার করে) will
বেশিরভাগ ক্যালকুলেটররা এই সমস্যাটি পেতে অতিরিক্ত গার্ড ডিজিট ব্যবহার করেন , যা কীভাবে 0.1 + 0.2
দেবে 0.3
: চূড়ান্ত কয়েকটি বিটকে গোল করা হয়।
কম্পিউটারে সঞ্চিত ফ্লোটিং পয়েন্ট সংখ্যা দুটি অংশ, একটি পূর্ণসংখ্যা এবং একটি ঘনিষ্ঠ সমন্বয়ে গঠিত হয় যা বেসকে নেওয়া হয় এবং পূর্ণসংখ্যার অংশ দ্বারা গুণিত হয়।
কম্পিউটার যদি বেস 10 এ কাজ করছিল, 0.1
হবে 1 x 10⁻¹
, 0.2
হবে 2 x 10⁻¹
এবং 0.3
হবে 3 x 10⁻¹
। পূর্ণসংখ্যার গণিত সহজ এবং নির্ভুল, সুতরাং যোগ 0.1 + 0.2
করলে স্পষ্টতই ফলাফল আসবে 0.3
।
কম্পিউটার সাধারণত বেস 10 কাজ করে না, তারা বেস 2. কাজ আপনি এখনও কিছু মান জন্য সঠিক ফলাফল পেতে পারেন, উদাহরণস্বরূপ 0.5
হয় 1 x 2⁻¹
এবং 0.25
হয় 1 x 2⁻²
, এবং তাদের যুক্ত করতে ফলাফল 3 x 2⁻²
, বা 0.75
। যথাযথভাবে।
সমস্যাটি এমন সংখ্যাগুলির সাথে আসে যা 10 টি বেসে হুবহু উপস্থাপন করা যেতে পারে তবে 2 বেসে নয় Those এই সংখ্যাগুলি তাদের নিকটতম সমতুল্যকে গোল করতে হবে। খুব সাধারণ আইইইই 64-বিট ফ্লোটিং পয়েন্ট ফরম্যাট, নিকটস্থ সংখ্যা ধরে নেওয়া যাক 0.1
হয় 3602879701896397 x 2⁻⁵⁵
, এবং নিকটস্থ সংখ্যা 0.2
হয় 7205759403792794 x 2⁻⁵⁵
; এগুলি একসাথে যুক্ত করলে ফলাফল 10808639105689191 x 2⁻⁵⁵
, বা এর দশমিক মান 0.3000000000000000444089209850062616169452667236328125
। ফ্লোটিং পয়েন্ট নম্বরগুলি সাধারণত প্রদর্শনের জন্য গোল হয়।
ভাসমান পয়েন্ট রাউন্ডিং ত্রুটি। প্রতিটি কম্পিউটার বিজ্ঞানী ভাসমান-পয়েন্ট পাটিগণিত সম্পর্কে যা জানা উচিত তা থেকে :
সীমিত সংখ্যক বিটগুলিতে অসীম অনেকগুলি আসল সংখ্যার পিছু হ্রাস করার জন্য একটি আনুমানিক উপস্থাপনা প্রয়োজন। যদিও অসীম অনেকগুলি পূর্ণসংখ্যা রয়েছে, বেশিরভাগ প্রোগ্রামে পূর্ণসংখ্যার গণনার ফলাফল 32 বিটগুলিতে সংরক্ষণ করা যায়। বিপরীতে, বিটগুলির যে কোনও নির্দিষ্ট সংখ্যক দেওয়া, আসল সংখ্যার সাথে সর্বাধিক গণনাগুলি এমন পরিমাণ তৈরি করবে যা সেই বিটগুলি ব্যবহার করে সঠিকভাবে প্রতিনিধিত্ব করা যায় না। সুতরাং তার সীমাবদ্ধ প্রতিনিধিত্বের পিছনে ফিটার জন্য ভাসমান-পয়েন্ট গণনার ফলাফলটি প্রায়শই গোল করা উচিত। এই বৃত্তাকার ত্রুটিটি ভাসমান-পয়েন্ট গণনার বৈশিষ্ট্যযুক্ত বৈশিষ্ট্য।
প্রচুর ভাল উত্তর পোস্ট করা হয়েছে তবে আমি আরও একটি যুক্ত করতে চাই।
নেই সব নম্বরগুলির মাধ্যমে প্রতিনিধিত্ব করা যাবে ভাসে / ডাবলস উদাহরণস্বরূপ, সংখ্যা "0.2" IEEE754 ভাসা বিন্দু মান একক স্পষ্টতা হিসেবে "0,200000003" প্রতিনিধিত্ব করা হবে না।
হুডের নীচে স্টোর আসল সংখ্যার মডেল হিসাবে ভাসমান সংখ্যা উপস্থাপন করে
যদিও আপনি 0.2
সহজে টাইপ করতে পারেন, FLT_RADIX
এবং DBL_RADIX
এটি 2 হয়; এফপিইউ সহ এমন একটি কম্পিউটারের জন্য 10 নয় যা "বাইনারি ফ্লোটিং-পয়েন্ট এরিমেটিক (আইএসও / আইইইই স্ট্যান্ড 754-1985) জন্য আইইইই স্ট্যান্ডার্ড ব্যবহার করে"।
সুতরাং এই জাতীয় সংখ্যার সঠিকভাবে উপস্থাপন করা কিছুটা কঠিন is এমনকি যদি আপনি কোনও মধ্যবর্তী গণনা ছাড়াই এই পরিবর্তনশীলটি স্পষ্টভাবে নির্দিষ্ট করে থাকেন।
এই বিখ্যাত দ্বৈত নির্ভুলতা প্রশ্নের সাথে সম্পর্কিত কিছু পরিসংখ্যান।
0.1 এর একটি ধাপ (0.1 থেকে 100 পর্যন্ত) ব্যবহার করে সমস্ত মান ( a + b ) যুক্ত করার সময় আমাদের কাছে নির্ভুল ত্রুটির 15 ডলার সম্ভাবনা রয়েছে । নোট করুন যে ত্রুটির ফলে কিছুটা বড় বা ছোট মান হতে পারে। এখানে কিছু উদাহরন:
0.1 + 0.2 = 0.30000000000000004 (BIGGER)
0.1 + 0.7 = 0.7999999999999999 (SMALLER)
...
1.7 + 1.9 = 3.5999999999999996 (SMALLER)
1.7 + 2.2 = 3.9000000000000004 (BIGGER)
...
3.2 + 3.6 = 6.800000000000001 (BIGGER)
3.2 + 4.4 = 7.6000000000000005 (BIGGER)
সমস্ত মানকে বিয়োগ করার সময় ( a - b যেখানে a> খ ) 0.1 এর একটি ধাপ ব্যবহার করে (100 থেকে 0.1 পর্যন্ত) আমাদের নির্ভুলতা ত্রুটির 34% সম্ভাবনা রয়েছে । এখানে কিছু উদাহরন:
0.6 - 0.2 = 0.39999999999999997 (SMALLER)
0.5 - 0.4 = 0.09999999999999998 (SMALLER)
...
2.1 - 0.2 = 1.9000000000000001 (BIGGER)
2.0 - 1.9 = 0.10000000000000009 (BIGGER)
...
100 - 99.9 = 0.09999999999999432 (SMALLER)
100 - 99.8 = 0.20000000000000284 (BIGGER)
* 15% এবং 34% প্রকৃতপক্ষে বিশাল, তাই যথার্থতা যখন গুরুত্বপূর্ণ হয় তখন সর্বদা বিগডিসিমাল ব্যবহার করুন। 2 দশমিক সংখ্যা (0.01 ধাপ) এর সাহায্যে পরিস্থিতি কিছুটা আরও খারাপ হয় (18% এবং 36%)।
সারসংক্ষেপ
ফ্লোটিং পয়েন্ট গাণিতিক হয় সঠিক, দুর্ভাগ্যবশত, এটা বজায় ভাল আমাদের স্বাভাবিক 10-ভিত্তিক নম্বর উপস্থাপনাতে সঙ্গে মেলে না, তাই এটি সক্রিয় আউট আমরা প্রায়ই এটা ইনপুট যে সামান্য আমরা কি লিখেছিলেন থেকে বন্ধ রয়েছে দিচ্ছেন।
এমনকি 0.01, 0.02, 0.03, 0.04 ... 0.24 এর মতো সাধারণ সংখ্যা বাইনারি ভগ্নাংশের মতো ঠিক উপস্থাপনযোগ্য নয়। আপনি যদি 0.01, .02, .03 ... গণনা করেন তবে 0.25 না হওয়া পর্যন্ত আপনি বেস 2 তে প্রথম ভগ্নাংশ উপস্থাপনযোগ্য পাবেন । যদি আপনি চেষ্টা করে থাকেন যে এফপি ব্যবহার করে, আপনার 0.01 কিছুটা বন্ধ হয়ে গেছে, সুতরাং তাদের 25 টিকে একটি দুর্দান্ত সঠিক 0.25 পর্যন্ত যুক্ত করার একমাত্র উপায়টির জন্য গার্ড বিটস এবং রাউন্ডিং জড়িত কার্যকারিতার দীর্ঘ শৃঙ্খলার প্রয়োজন হত। এটি পূর্বাভাস দেওয়া খুব শক্ত তাই আমরা হাত বাড়িয়ে বলি "এফপি নিখরচায়", তবে এটি সত্য নয়।
আমরা ক্রমাগত এফপি হার্ডওয়্যার এমন কিছু দিয়ে থাকি যা বেস 10 এ সহজ বলে মনে হয় তবে এটি বেস 2 এর পুনরাবৃত্তি ভগ্নাংশ।
এটা কিভাবে হল?
যখন আমরা দশমিকভাবে লিখি, প্রতিটি ভগ্নাংশ (বিশেষত, প্রতিটি সমাপ্তি দশমিক) ফর্মের যুক্তিযুক্ত সংখ্যা
এ / (২ এন x 5 মি )
বাইনারি-তে, আমরা কেবল 2 এন পদ পাই , তা হ'ল:
ক / 2 এন
সুতরাং দশমিক, আমরা উপস্থাপন করতে পারবেন না 1 / 3 । কারণ বেস 10 একটি মৌলিক ফ্যাক্টর হিসেবে 2 অন্তর্ভুক্ত, যে সংখ্যা আমরা একটি বাইনারি ভগ্নাংশ হিসাবে লিখতে পারেন এছাড়াও একটি বেস 10 ভগ্নাংশ হিসাবে লেখা যেতে পারে। তবে, বেস 10 ভগ্নাংশ হিসাবে আমরা খুব কমই লিখি বাইনারি হিসাবে উপস্থাপনযোগ্য। ০.০১, ০.০২, ০.০৩ ... ০.৯৯ থেকে মাত্র তিনটি সংখ্যাকেই আমাদের এফপি ফর্ম্যাটে প্রতিনিধিত্ব করা যেতে পারে: 0.25, 0.50 এবং 0.75, কারণ এগুলি সমস্ত সংখ্যা 1/4, 1/2, এবং 3/4, সমস্ত সংখ্যা শুধুমাত্র 2 এন পদ ব্যবহার করে একটি মৌলিক ফ্যাক্টর সহ ।
বেস 10 আমরা উপস্থাপন করতে পারবেন না 1 / 3 । কিন্তু বাইনারি, আমরা করতে পারবো না 1 / 10 বা 1 / 3 ।
সুতরাং প্রতিটি বাইনারি ভগ্নাংশ দশমিক লেখা যেতে পারে, বিপরীতটি সত্য নয়। এবং আসলে বেশিরভাগ দশমিক ভগ্নাংশ বাইনারিতে পুনরাবৃত্তি করে।
এটির সাথে ডিল করছে
বিকাশকারীদের সাধারণত <অ্যাপসিলন তুলনা করার জন্য নির্দেশ দেওয়া হয় , আরও ভাল পরামর্শ অবিচ্ছেদ্য মানগুলিতে গোল করা (সি লাইব্রেরিতে: বৃত্তাকার () এবং রাউন্ডফ () অর্থাত্, এফপি ফর্ম্যাটে থাকুন) এবং তারপরে তুলনা করতে পারেন। নির্দিষ্ট দশমিক ভগ্নাংশ দৈর্ঘ্যে গোল করা আউটপুট নিয়ে সর্বাধিক সমস্যার সমাধান করে।
এছাড়াও, আসল সংখ্যা-ক্রাঞ্চিং সমস্যাগুলিতে (প্রথম দিকে, ভয়াবহ ব্যয়বহুল কম্পিউটারগুলির জন্য এফপি উদ্ভাবন করা হয়েছিল) মহাবিশ্বের শারীরিক ধ্রুবক এবং অন্যান্য সমস্ত পরিমাপ কেবল অপেক্ষাকৃত কম সংখ্যক উল্লেখযোগ্য ব্যক্তির কাছেই পরিচিত, সুতরাং সম্পূর্ণ সমস্যার স্থান যাইহোক "অনর্থক" ছিল। এই জাতীয় প্রয়োগে এফপি "নির্ভুলতা" কোনও সমস্যা নয়।
লোকেরা শিম গণনার জন্য এফপি ব্যবহার করার চেষ্টা করার সময় পুরো বিষয়টি সত্যিই দেখা দেয়। এটি তার জন্য কাজ করে, তবে কেবলমাত্র যদি আপনি অবিচ্ছেদ্য মানগুলিতে লেগে থাকেন তবে কোন ধরণের এটি ব্যবহারের বিন্দুকে পরাস্ত করে। এই কারণেই আমাদের কাছে সমস্ত দশমিক ভগ্নাংশ সফ্টওয়্যার লাইব্রেরি রয়েছে।
আমি ক্রিসের পিৎজার উত্তরটি পছন্দ করি , কারণ এটি "ভুলত্রুটি" সম্পর্কে সাধারণ হ্যান্ডউইভিংকেই নয়, আসল সমস্যাটি বর্ণনা করে। যদি এফপি কেবল "ভুল" হয় তবে আমরা তা ঠিক করতে পারতাম এবং কয়েক দশক আগে এটি করতাম। আমাদের না হওয়ার কারণ হ'ল এফপি ফর্ম্যাটটি কমপ্যাক্ট এবং দ্রুত এবং এটি প্রচুর সংখ্যার ক্রাঙ্ক করার সেরা উপায়। এছাড়াও, এটি মহাকাশ বয়স এবং অস্ত্রের দৌড়ের একটি উত্তরাধিকার এবং ছোট স্মৃতি সিস্টেম ব্যবহার করে খুব ধীর কম্পিউটারের মাধ্যমে বড় সমস্যাগুলি সমাধান করার প্রাথমিক প্রচেষ্টা। (কখনও কখনও, পৃথক 1-বিট স্টোরেজের জন্য চৌম্বকীয় কোর , তবে এটি অন্য গল্প )
উপসংহার
যদি আপনি কেবল একটি ব্যাংকে মটরশুটি গণনা করেন তবে প্রথম স্থানে দশমিক স্ট্রিংয়ের উপস্থাপনা ব্যবহার করে এমন সফ্টওয়্যার সমাধান পুরোপুরি ভালভাবে কাজ করে। তবে আপনি কোয়ান্টাম ক্রোমোডাইনামিক্স বা বায়বীয়তাবিদ্যা সেভাবে করতে পারবেন না।
nextafter()
কোনও আইইইই ফ্লোটের বাইনারি উপস্থাপনায় পূর্ণসংখ্যা বৃদ্ধি বা হ্রাস সহ প্রয়োগ করতে পারেন । এছাড়াও, আপনি পূর্ণসংখ্যার হিসাবে ভাসমানগুলির তুলনা করতে পারেন এবং উভয় নেতিবাচক হওয়া ব্যতীত সঠিক উত্তর পেতে পারেন (কারণ সাইন-প্রস্থের তুলনায় 2 এর পরিপূরক)।
আপনি কি নালী টেপ সমাধান চেষ্টা করে?
ত্রুটিগুলি কখন সংঘটিত হয় তা নির্ধারণ করার চেষ্টা করুন এবং বিবৃতিগুলি সংক্ষেপে সংশোধন করুন, এটি সুন্দর নয় তবে কিছু সমস্যার জন্য এটিই একমাত্র সমাধান এবং এটি তাদের মধ্যে একটি।
if( (n * 0.1) < 100.0 ) { return n * 0.1 - 0.000000000000001 ;}
else { return n * 0.1 + 0.000000000000001 ;}
সি # তে একটি বৈজ্ঞানিক সিমুলেশন প্রকল্পে আমার একই সমস্যা ছিল এবং আমি আপনাকে বলতে পারি যে আপনি যদি প্রজাপতির প্রভাব উপেক্ষা করেন তবে এটি একটি বড় ফ্যাট ড্রাগনে পরিণত হবে এবং আপনাকে ** তে কামড় দেবে
অর্ডার দিতে সালে সবচেয়ে ভালো সমাধান আমি বলতে পারি আমি পদ্ধতি নিম্নলিখিত আবিষ্কৃত:
parseFloat((0.1 + 0.2).toFixed(10)) => Will return 0.3
কেন এটি সেরা সমাধান তা আমাকে ব্যাখ্যা করুন। উপরের উত্তরে যেমন অন্যরা উল্লিখিত হয়েছে, সমস্যা সমাধানের জন্য জাভাস্ক্রিপ্ট থেকে ফিক্সড () ফাংশনটি ব্যবহারের জন্য প্রস্তুত ব্যবহার করা ভাল ধারণা। তবে সম্ভবত আপনি কিছু সমস্যার মুখোমুখি হবেন।
কল্পনা করুন আপনি দুটি ভাসমান সংখ্যা যুক্ত করতে যাচ্ছেন 0.2
এবং 0.7
এটি এখানে:0.2 + 0.7 = 0.8999999999999999
।
আপনার প্রত্যাশিত ফলাফলটির 0.9
অর্থ হ'ল এই ক্ষেত্রে আপনার 1 ডিজিট যথার্থতার সাথে ফলাফল দরকার। সুতরাং আপনার ব্যবহার করা উচিত ছিল (0.2 + 0.7).tofixed(1)
তবে আপনি ফিক্সড () কে কেবল একটি নির্দিষ্ট পরামিতি দিতে পারবেন না কারণ এটি প্রদত্ত সংখ্যার উপর নির্ভর করে, উদাহরণস্বরূপ
`0.22 + 0.7 = 0.9199999999999999`
এই উদাহরণে আপনার 2 ডিজিটের যথার্থতা প্রয়োজন তাই এটি হওয়া উচিত toFixed(2)
, তাই প্রতিটি প্রদত্ত ফ্লোট সংখ্যাটি ফিট করার জন্য পরামিতিটি কী হওয়া উচিত?
আপনি বলতে পারেন যে এটি প্রতিটি পরিস্থিতিতে এটি 10 হতে দিন:
(0.2 + 0.7).toFixed(10) => Result will be "0.9000000000"
অভিশাপ! 9 এর পরে আপনি সেই অযাচিত জিরোগুলি কী করতে যাচ্ছেন? আপনার ইচ্ছামতো তৈরি করার জন্য এটি এটিকে ফ্লোটে রূপান্তর করার সময়:
parseFloat((0.2 + 0.7).toFixed(10)) => Result will be 0.9
এখন আপনি যে সমাধানটি পেয়েছেন, এটি এটির মতো কার্যকারিতা হিসাবে দেওয়া ভাল:
function floatify(number){
return parseFloat((number).toFixed(10));
}
আসুন এটি চেষ্টা করুন:
function floatify(number){
return parseFloat((number).toFixed(10));
}
function addUp(){
var number1 = +$("#number1").val();
var number2 = +$("#number2").val();
var unexpectedResult = number1 + number2;
var expectedResult = floatify(number1 + number2);
$("#unexpectedResult").text(unexpectedResult);
$("#expectedResult").text(expectedResult);
}
addUp();
input{
width: 50px;
}
#expectedResult{
color: green;
}
#unexpectedResult{
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="number1" value="0.2" onclick="addUp()" onkeyup="addUp()"/> +
<input id="number2" value="0.7" onclick="addUp()" onkeyup="addUp()"/> =
<p>Expected Result: <span id="expectedResult"></span></p>
<p>Unexpected Result: <span id="unexpectedResult"></span></p>
আপনি এটি এইভাবে ব্যবহার করতে পারেন:
var x = 0.2 + 0.7;
floatify(x); => Result: 0.9
হিসাবে W3Schools প্রস্তাব দেওয়া আরেকটা সমাধান খুব হয়, তাহলে আপনি গুন করতে পারেন এবং ডিভাইড উপরে সমস্যা সমাধানের জন্য:
var x = (0.2 * 10 + 0.1 * 10) / 10; // x will be 0.3
মনে (0.2 + 0.1) * 10 / 10
হবেন যে এগুলি একই মনে হলেও এগুলি কার্যকর হবে না! আমি প্রথম সমাধানটি পছন্দ করি যেহেতু আমি এটিকে একটি ফাংশন হিসাবে প্রয়োগ করতে পারি যা ইনপুট ফ্লোটকে সঠিক আউটপুট ফ্লোটে রূপান্তর করে।
কম্পিউটারগুলি গণনার উদ্দেশ্যে বাইনারি (বেস 2) নম্বর সিস্টেম ব্যবহার করে কারণ আমরা দশমিক (বেস 10) ব্যবহার করি কারণ এই অদ্ভুত সংখ্যাগুলি উপস্থিত হয়।
সংখ্যাগরিষ্ঠ সংখ্যাগরিষ্ঠ রয়েছে যা বাইনারি বা দশমিক বা উভয় ক্ষেত্রেই যথাযথভাবে উপস্থাপন করা যায় না। ফলাফল - একটি বৃত্তাকার আপ (তবে সুনির্দিষ্ট) সংখ্যার ফলাফল।
এই প্রশ্নের অসংখ্য ডুপ্লিকেটগুলি বেশ কয়েকটি নির্দিষ্ট সংখ্যার উপরে ভাসমান পয়েন্টের প্রভাব সম্পর্কে জিজ্ঞাসা করে। বাস্তবে, কেবল এটি পড়ার চেয়ে আগ্রহের গণনার সঠিক ফলাফলগুলি দেখে এটি কীভাবে কাজ করে তার অনুভূতি পাওয়া সহজ। কিছু ভাষা সেগুলি করার উপায় সরবরাহ করে - যেমন একটি float
বা রূপান্তরিত double
করার মতোBigDecimal
জাভা।
যেহেতু এটি একটি ভাষা-অজ্ঞাত প্রশ্ন, তাই এর জন্য ভাষা-অজ্ঞাস্তিক সরঞ্জামগুলির দরকার যেমন ডেসিমাল থেকে ফ্লোটিং-পয়েন্ট রূপান্তরকারী ।
দ্বিগুণ হিসাবে বিবেচিত, প্রশ্নের নম্বরগুলিতে এটি প্রয়োগ করা:
0.1 রূপান্তর 0.1000000000000000055511151231257827021181583404541015625,
0.2 0.200000000000000000011102230246251565404236316680908203125 এ রূপান্তর করে,
০.০ রূপান্তরিত হয় 0.299999999999999988897769753748434595763683319091796875, এবং
0.3000000000000000004 0.3000000000000000444089209850062616169452667236328125 এ রূপান্তর করে।
প্রথম দুটি সংখ্যা ম্যানুয়ালি বা দশমিক ক্যালকুলেটর যেমন সম্পূর্ণ যথার্থ ক্যালকুলেটরে যুক্ত করা প্রকৃত ইনপুটগুলির সঠিক যোগফল 0.3000000000000000166533453693773481063544750213623046875 দেখায়।
এটি যদি 0.3 এর সমতুল্য হয়ে থাকে তবে রাউন্ডিং ত্রুটিটি 0.0000000000000000277555756156289135105907917022705078125 হবে। 0.3000000000000000004 এর সমতুল্যকে গোল করা এছাড়াও রাউন্ডিং ত্রুটি 0.000000000000000000277555756156289135105907917022705078125 দেয়। রাউন্ড টু-ইন্-টাই টাই ব্রেকার প্রযোজ্য।
ভাসমান বিন্দু রূপান্তরকারীটিতে ফিরে, 0.3000000000000000004 এর কাঁচা হেক্সাডেসিমাল 3fd333333333333334, যা একটি এমনকি সংখ্যায় শেষ হয় এবং তাই সঠিক ফলাফল।
দেওয়া হয়েছে যে কেউ এটি উল্লেখ করেছে ...
পাইথন এবং জাভা এর মতো কয়েকটি উচ্চ স্তরের ভাষা বাইনারি ভাসমান পয়েন্টের সীমাবদ্ধতাগুলি অতিক্রম করার সরঞ্জাম নিয়ে আসে। উদাহরণ স্বরূপ:
পাইথনের decimal
মডিউল এবং জাভার BigDecimal
ক্লাস , যা দশমিক স্বরলিপি (বাইনারি স্বীকৃতির বিপরীতে) সহ অভ্যন্তরীণভাবে প্রতিনিধিত্ব করে। উভয়েরই স্পষ্টতা সীমিত রয়েছে, তাই তারা এখনও ত্রুটিযুক্ত প্রবণ, তবে তারা বাইনারি ভাসমান পয়েন্ট গণিতের সাথে সর্বাধিক সাধারণ সমস্যার সমাধান করে।
অর্থের সাথে লেনদেন করার সময় দশমিকগুলি খুব সুন্দর: দশ সেন্ট প্লাস বিশ সেন্ট সবসময় হ'ল ত্রিশ সেন্ট:
>>> 0.1 + 0.2 == 0.3
False
>>> Decimal('0.1') + Decimal('0.2') == Decimal('0.3')
True
পাইথনের decimal
মডিউল আইইইই স্ট্যান্ডার্ড 854-1987 এর উপর ভিত্তি করে ।
পাইথনের fractions
মডিউল এবং অ্যাপাচি সাধারণের BigFraction
ক্লাস । উভয়ই যুক্ত হিসাবে যুক্তিযুক্ত সংখ্যা উপস্থাপন করে (numerator, denominator)
এবং তারা দশমিক ভাসমান পয়েন্ট গণিতের চেয়ে আরও সঠিক ফলাফল দিতে পারে।
এই সমাধানগুলির কোনওটিই নিখুঁত নয় (বিশেষত যদি আমরা পারফরম্যান্সগুলি দেখি, বা যদি আমাদের খুব উচ্চ নির্ভুলতার প্রয়োজন হয়) তবে তবুও তারা বাইনারি ভাসমান পয়েন্ট গণিতের সাথে একটি বিশাল সংখ্যক সমস্যা সমাধান করে।
আমি কি যুক্ত করতে পারি; লোকেদের সর্বদা এটি একটি কম্পিউটার সমস্যা হিসাবে ধরে নিয়েছে, তবে আপনি যদি নিজের হাতে (বেস 10) গণনা করেন (1/3+1/3=2/3)=true
তবে আপনার কাছে 0.333 ... 0.3.3 যোগ করার মতো অসীমতা না থাকলে আপনি পাবেন না ... ঠিক তেমনি (1/10+2/10)!==3/10
বেসের সমস্যার সাথেও 2, আপনি এটি 0.333 + 0.333 = 0.666 এ ছাঁটাই করেছেন এবং সম্ভবত এটি 0.667 এ গোল করবেন যা প্রযুক্তিগতভাবেও ভুল হবে।
ত্রৈমাসিক হিসাবে গণনা করুন, এবং তৃতীয়াংশ কোনও সমস্যা নয় যদিও - সম্ভবত প্রতিটি হাতে 15 টি আঙ্গুল দিয়ে কিছু রেস জিজ্ঞাসা করবে কেন আপনার দশমিক গণিতটি ভেঙে গেছে ...
ডিজিটাল কম্পিউটারে যে ধরণের ভাসমান-পয়েন্ট গণিত করা যেতে পারে তা অগত্যা তাদের বাস্তব সংখ্যাগুলির সংলগ্নতা এবং তাদের উপর ক্রিয়াকলাপ ব্যবহার করে। ( স্ট্যান্ডার্ড সংস্করণটি পঞ্চাশ পৃষ্ঠার ডকুমেন্টেশনের দিকে চলে এবং এরটি এবং আরও পরিমার্জনকে মোকাবেলায় একটি কমিটি রয়েছে has)
এই অনুমানটি হ'ল বিভিন্ন ধরণের অনুমানের মিশ্রণ, যার প্রতিটিটি যথাযথতা থেকে বিচ্যুত হওয়ার নির্দিষ্ট পদ্ধতিগুলির কারণে উপেক্ষা করা বা সাবধানতার সাথে গণ্য করা যেতে পারে। এটি হার্ডওয়্যার এবং সফ্টওয়্যার উভয় স্তরের বেশ কয়েকটি সুস্পষ্ট ব্যতিক্রমী মামলা জড়িত যা বেশিরভাগ মানুষ খেয়াল না করার ভান করে সঠিক অতীতে চলে।
আপনার যদি অসীম নির্ভুলতার প্রয়োজন হয় (উদাহরণটি using ব্যবহার করে, উদাহরণস্বরূপ, এর অনেকগুলি সংক্ষিপ্ত স্ট্যান্ড-ইনগুলির পরিবর্তে) আপনার পরিবর্তে একটি প্রতীকী গণিত প্রোগ্রাম লিখতে বা ব্যবহার করা উচিত।
তবে যদি আপনি এই ধারণাটি থেকে ঠিক থাকেন যে মাঝে মাঝে ভাসমান-পয়েন্ট গণিতটি মূল্যবোধে অস্পষ্ট হয় এবং যুক্তিগুলি এবং ত্রুটিগুলি দ্রুত জমা হতে পারে এবং এটির জন্য আপনি আপনার প্রয়োজনীয়তা এবং পরীক্ষাগুলি লিখতে পারেন তবে আপনার কোডটি যা আছে তা দিয়ে প্রায়শই পেতে পারে আপনার এফপিইউ
কেবল মজাদার জন্য, আমি স্ট্যান্ডার্ড সি 99 এর সংজ্ঞাগুলি অনুসরণ করে ভাসমানদের প্রতিনিধিত্ব করে খেললাম এবং আমি নীচের কোডটি লিখেছি।
কোডটি 3 টি পৃথক গ্রুপে ভাসমানদের বাইনারি উপস্থাপনা মুদ্রণ করে
SIGN EXPONENT FRACTION
এবং তারপরে এটি একটি যোগফল মুদ্রণ করে, এটি পর্যাপ্ত নির্ভুলতার সাথে যোগ করা হলে, হার্ডওয়্যারে প্রকৃত উপস্থিতিটির মানটি প্রদর্শিত হবে।
সুতরাং আপনি যখন লিখবেন float x = 999...
, সংকলকটি ফাংশন দ্বারা মুদ্রিত কিছু উপস্থাপনায় number সংখ্যাটিকে রূপান্তর করবে xx
যেমন ফাংশন দ্বারা মুদ্রিত সমষ্টিyy
প্রদত্ত সংখ্যার সমান হয়।
বাস্তবে, এই যোগফলটি কেবল একটি আনুমানিক। 999,999,999 সংখ্যার জন্য সংকলকটি 1000,000,000 সংখ্যাটির সামান্য প্রতিনিধিত্ব করে সন্নিবেশ করবে
কোডের পরে আমি একটি কনসোল সেশন সংযুক্ত করি, যেখানে আমি উভয় ধ্রুবক (বিয়োগ পিআই এবং 999999999) এর শর্তগুলির যোগফল গণনা করি যা হার্ডওয়্যারে সত্যই বিদ্যমান, সংকলক দ্বারা সেখানে sertedোকানো হয়েছিল।
#include <stdio.h>
#include <limits.h>
void
xx(float *x)
{
unsigned char i = sizeof(*x)*CHAR_BIT-1;
do {
switch (i) {
case 31:
printf("sign:");
break;
case 30:
printf("exponent:");
break;
case 23:
printf("fraction:");
break;
}
char b=(*(unsigned long long*)x&((unsigned long long)1<<i))!=0;
printf("%d ", b);
} while (i--);
printf("\n");
}
void
yy(float a)
{
int sign=!(*(unsigned long long*)&a&((unsigned long long)1<<31));
int fraction = ((1<<23)-1)&(*(int*)&a);
int exponent = (255&((*(int*)&a)>>23))-127;
printf(sign?"positive" " ( 1+":"negative" " ( 1+");
unsigned int i = 1<<22;
unsigned int j = 1;
do {
char b=(fraction&i)!=0;
b&&(printf("1/(%d) %c", 1<<j, (fraction&(i-1))?'+':')' ), 0);
} while (j++, i>>=1);
printf("*2^%d", exponent);
printf("\n");
}
void
main()
{
float x=-3.14;
float y=999999999;
printf("%lu\n", sizeof(x));
xx(&x);
xx(&y);
yy(x);
yy(y);
}
এখানে একটি কনসোল সেশন রয়েছে যাতে আমি হার্ডওয়্যারটিতে বিদ্যমান ভাসমানের আসল মানটি গণনা করি। আমি bc
মূল প্রোগ্রাম দ্বারা আউটপুট পদগুলির যোগফল মুদ্রণ করতে ব্যবহৃত । যে পাইটি পাইথন repl
বা অনুরূপ কিছু সন্নিবেশ করতে পারে।
-- .../terra1/stub
@ qemacs f.c
-- .../terra1/stub
@ gcc f.c
-- .../terra1/stub
@ ./a.out
sign:1 exponent:1 0 0 0 0 0 0 fraction:0 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 0 1 1
sign:0 exponent:1 0 0 1 1 1 0 fraction:0 1 1 0 1 1 1 0 0 1 1 0 1 0 1 1 0 0 1 0 1 0 0 0
negative ( 1+1/(2) +1/(16) +1/(256) +1/(512) +1/(1024) +1/(2048) +1/(8192) +1/(32768) +1/(65536) +1/(131072) +1/(4194304) +1/(8388608) )*2^1
positive ( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
-- .../terra1/stub
@ bc
scale=15
( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
999999999.999999446351872
এটাই. 999999999 এর মানটি আসলে
999999999.999999446351872
আপনি bc
যেটি পরীক্ষা করতে পারেন -3.14 এছাড়াও বিচলিত হয়। একটি scale
ফ্যাক্টর সেট করতে ভুলবেন না bc
।
প্রদর্শিত যোগফলটি হার্ডওয়্যারের অভ্যন্তরে। এটি গণনা করে আপনি যে মূল্য অর্জন করেন তা আপনার সেট করা স্কেলের উপর নির্ভর করে। আমি scale
ফ্যাক্টরটিকে 15 এ সেট করেছিলাম M
এটি দেখার আরও একটি উপায়: সংখ্যার প্রতিনিধিত্ব করতে 64 বিট ব্যবহৃত হয়। ফলস্বরূপ 2 ** ,৪ = 18,446,744,073,709,551,616 এর চেয়ে বেশি উপায় নেই different বিভিন্ন সংখ্যা যথাযথভাবে উপস্থাপিত হতে পারে।
যাইহোক, ম্যাথ বলছে যে 0 এবং 1 এর মধ্যে ইতিমধ্যে অসীম অনেকগুলি দশমিক রয়েছে are আইইই 754 এই 64 বিটগুলি আরও বেশি সংখ্যক স্থান প্লাস NaN এবং +/- অনন্ততার জন্য দক্ষতার সাথে ব্যবহার করার জন্য একটি এনকোডিংকে সংজ্ঞায়িত করে, তাই নির্ভুলভাবে প্রতিনিধিত্ব করা সংখ্যার মধ্যে ফাঁক রয়েছে সংখ্যাগুলি প্রায় আনুমানিক।
দুর্ভাগ্যক্রমে 0.3 একটি ফাঁকে বসে।
বেজ টেনে কাজ করার কথাটি কল করুন, বলুন, যথার্থতার 8 টি সংখ্যা। আপনি পরীক্ষা করে দেখুন কিনা
1/3 + 2 / 3 == 1
এবং শিখুন যে এই ফিরে আসে false
। কেন? ঠিক আছে, আমাদের কাছে আসল সংখ্যা রয়েছে
1/3 = 0.333 .... এবং 2/3 = 0.666 ....
আট দশমিক জায়গায় ছাঁটাই, আমরা পাই
0.33333333 + 0.66666666 = 0.99999999
যা অবশ্যই 1.00000000
একেবারে থেকে আলাদা 0.00000001
।
একটি নির্দিষ্ট সংখ্যক বিটের বাইনারি সংখ্যার পরিস্থিতি হুবহু অভিন্ন। আসল সংখ্যা হিসাবে, আমাদের আছে
1/10 = 0.0001100110011001100 ... (বেস 2)
এবং
1/5 = 0.0011001100110011001 ... (বেস 2)
যদি আমরা এগুলিকে সাতটি বিট কেটে ফেলে বলি, তবে আমরা পেয়ে যাব
0.0001100 + 0.0011001 = 0.0100101
অন্যদিকে,
3/10 = 0.01001100110011 ... (বেস 2)
যা সাতটি বিটকে কাটা হয়েছে 0.0100110
, এবং এগুলি একেবারে পৃথক 0.0000001
।
সঠিক পরিস্থিতি কিছুটা সূক্ষ্ম কারণ এই সংখ্যাগুলি সাধারণত বৈজ্ঞানিক স্বরলিপিতে সংরক্ষণ করা হয়। সুতরাং, উদাহরণস্বরূপ, 1/10 সংরক্ষণ করার পরিবর্তে 0.0001100
আমরা এটিকে কিছু পছন্দ করে রাখতে পারি1.10011 * 2^-4
, আমরা খাঁটি এবং ম্যান্টিসার জন্য কত বিট বরাদ্দ করেছি তার উপর নির্ভর করে। এটি আপনার গণনার জন্য কত সংখ্যক নির্ভুলতা পেয়েছে তা প্রভাবিত করে।
আপশটটি হ'ল এই রাউন্ডিং ত্রুটির কারণে আপনি মূলত কখনও ভাসমান-পয়েন্ট সংখ্যায় == ব্যবহার করতে চান না। পরিবর্তে, আপনি কিছু নির্দিষ্ট সংখ্যার চেয়ে তাদের পার্থক্যের পরম মানটি ছোট কিনা তা পরীক্ষা করতে পারেন।
পাইথন ৩.৩ যেহেতুmath.isclose()
আনুমানিক সমতা পরীক্ষার জন্য আপনি ফাংশনটি ব্যবহার করতে পারেন :
>>> import math
>>> math.isclose(0.1 + 0.2, 0.3)
True
>>> 0.1 + 0.2 == 0.3
False
যেহেতু এই থ্রেডটি বর্তমান ভাসমান পয়েন্ট বাস্তবায়নের উপর একটি সাধারণ আলোচনার জন্য কিছুটা ছড়িয়ে পড়েছে আমি যুক্ত করব যে তাদের সমস্যাগুলি স্থির করার জন্য প্রকল্প রয়েছে।
উদাহরণস্বরূপ https://posithub.org/ দেখুন , যা পোজিট (এবং এর পূর্বসূরি আনম) নামক একটি সংখ্যার প্রকার প্রদর্শন করে যা কম বিট দিয়ে আরও ভাল নির্ভুলতার প্রস্তাব দেয়। যদি আমার বোঝাপড়াটি সঠিক হয় তবে এটি প্রশ্নের ধরণের সমস্যাগুলিও ঠিক করে দেয়। বেশ আকর্ষণীয় প্রকল্প, এর পিছনে ব্যক্তি গণিতবিদ এটি ডঃ জন গুস্তাফসন । পুরো জিনিসটি ওপেন সোর্স, সি / সি ++, পাইথন, জুলিয়া এবং সি # ( https://hastlayer.com/arithmetics ) এর অনেকগুলি বাস্তব বাস্তবায়ন সহ ।
এটি আসলে বেশ সহজ। আপনার যদি বেস 10 সিস্টেম থাকে (আমাদের মতো), এটি কেবলমাত্র ভগ্নাংশ প্রকাশ করতে পারে যা বেসের একটি প্রধান উপাদান ব্যবহার করে। 10 এর প্রধান গুণকগুলি 2 এবং 5 হয়। সুতরাং 1/2, 1/4, 1/5, 1/8, এবং 1/10 সমস্ত পরিষ্কারভাবে প্রকাশ করা যেতে পারে কারণ ডিনোটেটররা 10 এর প্রধান উপাদান ব্যবহার করে বিপরীতে, 1 / 3, 1/6, এবং 1/7 সমস্তই দশমিক পুনরাবৃত্তি কারণ তাদের ডিনোমিনেটর 3 বা 7 এর একটি মৌলিক গুণক ব্যবহার করে বাইনারি (বা বেস 2) এ একমাত্র প্রধান ফ্যাক্টর 2 তাই আপনি কেবল ভগ্নাংশ পরিষ্কারভাবে প্রকাশ করতে পারবেন যা একটি প্রধান উপাদান হিসাবে কেবল 2 থাকে। বাইনারি, 1/2, 1/4, 1/8 সবই দশমিক হিসাবে পরিষ্কারভাবে প্রকাশ করা হবে। যখন, 1/5 বা 1/10 দশমিক পুনরাবৃত্তি হবে। সুতরাং 0.1 এবং 0.2 (1/10 এবং 1/5) যখন বেস 10 সিস্টেমে পরিষ্কার দশমিকগুলি, বেস 2 সিস্টেমে দশমিকগুলি পুনরাবৃত্তি করছে কম্পিউটারটি কাজ করছে When আপনি যখন এই পুনরাবৃত্তি দশমিকগুলিতে গণিত করেন,
যেমন ডেসিমাল সংখ্যা 0.1
, 0.2
এবং 0.3
বাইনারি ঠিক প্রতিনিধিত্ব নেই ফ্লোটিং পয়েন্ট ধরনের এনকোড। জন্য অনুমান এর সমষ্টি 0.1
এবং 0.2
জন্য ব্যবহৃত পড়তা থেকে পৃথক 0.3
, অত এর মিথ্যা 0.1 + 0.2 == 0.3
হিসাবে আরো পরিষ্কারভাবে এখানে দেখা যাবে:
#include <stdio.h>
int main() {
printf("0.1 + 0.2 == 0.3 is %s\n", 0.1 + 0.2 == 0.3 ? "true" : "false");
printf("0.1 is %.23f\n", 0.1);
printf("0.2 is %.23f\n", 0.2);
printf("0.1 + 0.2 is %.23f\n", 0.1 + 0.2);
printf("0.3 is %.23f\n", 0.3);
printf("0.3 - (0.1 + 0.2) is %g\n", 0.3 - (0.1 + 0.2));
return 0;
}
আউটপুট:
0.1 + 0.2 == 0.3 is false
0.1 is 0.10000000000000000555112
0.2 is 0.20000000000000001110223
0.1 + 0.2 is 0.30000000000000004440892
0.3 is 0.29999999999999998889777
0.3 - (0.1 + 0.2) is -5.55112e-17
এই গণনাগুলি আরও নির্ভরযোগ্যতার সাথে মূল্যায়নের জন্য, আপনাকে ভাসমান পয়েন্টের মানগুলির জন্য দশমিক-ভিত্তিক উপস্থাপনা ব্যবহার করতে হবে। সি স্ট্যান্ডার্ড ডিফল্টরূপে এ জাতীয় ধরণগুলি নির্দিষ্ট করে না তবে প্রযুক্তিগত প্রতিবেদনে বর্ণিত এক্সটেনশন হিসাবে ।
_Decimal32
, _Decimal64
এবং _Decimal128
ধরনের আপনার সিস্টেমে উপলব্ধ হতে পারে (উদাহরণস্বরূপ, জিসিসি তাদের উপর সমর্থন নির্বাচিত লক্ষ্যমাত্রা কিন্তু ঝনঝন তাদের উপর সমর্থন করে না OS X এর )।
ম্যাথ.সাম (জাভাস্ক্রিপ্ট) .... অপারেটর প্রতিস্থাপনের ধরণ
.1 + .0001 + -.1 --> 0.00010000000000000286
Math.sum(.1 , .0001, -.1) --> 0.0001
Object.defineProperties(Math, {
sign: {
value: function (x) {
return x ? x < 0 ? -1 : 1 : 0;
}
},
precision: {
value: function (value, precision, type) {
var v = parseFloat(value),
p = Math.max(precision, 0) || 0,
t = type || 'round';
return (Math[t](v * Math.pow(10, p)) / Math.pow(10, p)).toFixed(p);
}
},
scientific_to_num: { // this is from https://gist.github.com/jiggzson
value: function (num) {
//if the number is in scientific notation remove it
if (/e/i.test(num)) {
var zero = '0',
parts = String(num).toLowerCase().split('e'), //split into coeff and exponent
e = parts.pop(), //store the exponential part
l = Math.abs(e), //get the number of zeros
sign = e / l,
coeff_array = parts[0].split('.');
if (sign === -1) {
num = zero + '.' + new Array(l).join(zero) + coeff_array.join('');
} else {
var dec = coeff_array[1];
if (dec)
l = l - dec.length;
num = coeff_array.join('') + new Array(l + 1).join(zero);
}
}
return num;
}
}
get_precision: {
value: function (number) {
var arr = Math.scientific_to_num((number + "")).split(".");
return arr[1] ? arr[1].length : 0;
}
},
sum: {
value: function () {
var prec = 0, sum = 0;
for (var i = 0; i < arguments.length; i++) {
prec = this.max(prec, this.get_precision(arguments[i]));
sum += +arguments[i]; // force float to convert strings to number
}
return Math.precision(sum, prec);
}
}
});
ধারণাটি হ'ল ফ্ল্যাটের ত্রুটিগুলি এড়াতে পরিবর্তে অপারেটরগুলি ম্যাথ ব্যবহার করা
ম্যাথ.সুম ব্যবহারের জন্য নির্ভুলতা সনাক্ত করে
ম্যাথ.সুম যেকোন সংখ্যক যুক্তি গ্রহণ করে
নিম্নলিখিত ফলাফল বিবেচনা করুন:
error = (2**53+1) - int(float(2**53+1))
>>> (2**53+1) - int(float(2**53+1))
1
আমরা স্পষ্টভাবে একটি ব্রেকপয়েন্ট দেখতে পারি যখন 2**53+1
- সমস্তক্ষণ অবধি কার্যকর থাকে 2**53
।
>>> (2**53) - int(float(2**53))
0
ডাবল-স্পষ্টতা বাইনারি কারণে এটি ঘটে: আইইইই 754 ডাবল-স্পষ্টতা বাইনারি ভাসমান-পয়েন্ট ফর্ম্যাট: বাইনারি 64
ডাবল-স্পষ্টতা ভাসমান-পয়েন্ট বিন্যাসের জন্য উইকিপিডিয়া পৃষ্ঠা থেকে :
ডাবল-স্পষ্টতা বাইনারি ফ্লোটিং পয়েন্ট হ'ল পিসিগুলিতে একটি সাধারণ ব্যবহৃত ফর্ম্যাট, এর পারফরম্যান্স এবং ব্যান্ডউইথ ব্যয় সত্ত্বেও একক-নির্ভুলতা ভাসমান পয়েন্টের বিস্তৃত সীমার কারণে। একক-নির্ভুলতা ভাসমান-বিন্দু বিন্যাসের মতো, একই আকারের পূর্ণসংখ্যার বিন্যাসের সাথে তুলনা করলে এটি পূর্ণসংখ্যার সংখ্যার সাথে যথাযথতার অভাব হয়। এটি সাধারণত দ্বিগুণ হিসাবে পরিচিত। আইইইই 754 স্ট্যান্ডার্ডটি বাইনারি 64 হিসাবে রয়েছে তা নির্দিষ্ট করে:
- সাইন বিট: 1 বিট
- ঘোষক: 11 বিট
- উল্লেখযোগ্য নির্ভুলতা: 53 বিট (52 স্পষ্টত সঞ্চিত)
প্রদত্ত পক্ষপাতিত্বকারী এক্সপোনেন্ট এবং 52-বিট ভগ্নাংশ সহ একটি প্রদত্ত 64-বিট ডাবল-স্পষ্টতা ডেটাম দ্বারা ধরে নেওয়া আসল মানটি
অথবা
আমাকে এটি নির্দেশ করার জন্য @a_guest কে ধন্যবাদ।
এটির একটি সদৃশ হিসাবে একটি অন্য প্রশ্নের নাম দেওয়া হয়েছে:
সি ++ এ, cout << x
কোনও ডিবাগার যে মানটি দেখায় তার থেকে আলাদা ফলাফল কেন x
?
x
প্রশ্নে একটি হল float
পরিবর্তনশীল।
একটি উদাহরণ হবে
float x = 9.9F;
ডিবাগারটি দেখায় 9.89999962
, cout
অপারেশন আউটপুট হয় 9.9
।
উত্তরটি সেই cout
ডিফল্ট নির্ভুলতার জন্য পরিণত হয়েছেfloat
6 হয়, সুতরাং এটি 6 দশমিক সংখ্যায় গোল হয়।
রেফারেন্সের জন্য এখানে দেখুন