পাইথন 3 তে 4 * 0.1 এর ভাসমান-পয়েন্টের মানটি দেখতে সুন্দর তবে 3 * 0.1 টি কেন লাগে না?


158

আমি জানি যে বেশিরভাগ দশমিকের সঠিক ভাসমান পয়েন্ট উপস্থাপনা থাকে না ( ভাসমান পয়েন্ট গণিতটি কি ভাঙা? )।

কিন্তু আমি দেখতে পাচ্ছি না কেন 4*0.1চমত্কারভাবে হিসাবে ছাপা হয় 0.4, কিন্তু 3*0.1যখন উভয় মান আসলে কুশ্রী দশমিক উপস্থাপনা নেই, হল:

>>> 3*0.1
0.30000000000000004
>>> 4*0.1
0.4
>>> from decimal import Decimal
>>> Decimal(3*0.1)
Decimal('0.3000000000000000444089209850062616169452667236328125')
>>> Decimal(4*0.1)
Decimal('0.40000000000000002220446049250313080847263336181640625')

7
কারণ কিছু সংখ্যা হুবহু উপস্থাপন করা যায়, এবং কিছু নাও পারে।
মরগান থ্রাপ

58
@ মরগানথ্রাপ: না, তা নয়। ওপি বরং স্বেচ্ছাসেবক চেহারা ফর্ম্যাটিং পছন্দ সম্পর্কে জিজ্ঞাসা করছে। 0.3 বা 0.4 উভয়ই বাইনারি ভাসমান পয়েন্টে হুবহু উপস্থাপন করা যায় না।
বৎশেবা

42
@BartoszKP: রয়ে ডকুমেন্ট বেশ কয়েকবার পড়ুন, এটি ব্যাখ্যা না কেন পাইথন প্রদর্শন করা হয় 0.3000000000000000444089209850062616169452667236328125যেমন 0.30000000000000004এবং 0.40000000000000002220446049250313080847263336181640625হিসাবে .4যদিও তারা একই সঠিকতা আছে প্রদর্শিত, এবং এইভাবে প্রশ্নের উত্তর নেই।
মাকিং হাঁস

6
এছাড়াও দেখুন স্ট্যাকওভারফ্লো.com / প্রশ্নগুলি / ২৮৯৩৫৫7//২ - আমি কিছুটা বিরক্ত হয়েছি যে এটি নকল হিসাবে বন্ধ হয়ে গেছে তবে এটি হয়নি।
র্যান্ডম 832

12
আবার খোলা, দয়া করে এটিকে বন্ধ করবেন না কারণ "এটি ভাসমান পয়েন্টের গণিত ভাঙা" এর সদৃশ
অ্যান্টি হাপালা

উত্তর:


301

সহজ উত্তরটি হ'ল কারণ 3*0.1 != 0.3কোয়ান্টাইজেশন (রাউন্ডঅফ) ত্রুটির কারণে (যেখানে 4*0.1 == 0.4দুটি জনের দ্বারা গুণন করা সাধারণত "সঠিক" অপারেশন হয়)।

.hexকোনও সংখ্যার অভ্যন্তরীণ উপস্থাপনা দেখতে আপনি পাইথনের পদ্ধতিটি ব্যবহার করতে পারেন (মূলত, বেস -10 অনুমানের চেয়ে সঠিক বাইনারি ভাসমান পয়েন্ট মান)। এটি হুডের নীচে কী চলছে তা ব্যাখ্যা করতে সহায়তা করতে পারে।

>>> (0.1).hex()
'0x1.999999999999ap-4'
>>> (0.3).hex()
'0x1.3333333333333p-2'
>>> (0.1*3).hex()
'0x1.3333333333334p-2'
>>> (0.4).hex()
'0x1.999999999999ap-2'
>>> (0.1*4).hex()
'0x1.999999999999ap-2'

0.1 হ'ল 0x1.999999999999a গুণ 2 ^ -4। শেষে "ক" এর অর্থ হ'ল অঙ্ক 10 - অন্য কথায়, বাইনারি ভাসমান বিন্দুতে 0.1 এর "সঠিক" মানের তুলনায় খুব সামান্য বড় (কারণ চূড়ান্ত 0x0.99 0x0.a পর্যন্ত গোল হয়)। আপনি যখন 4 এর গুণন করে, দু'জনের একটি শক্তি, ঘনিষ্ঠটি স্থানান্তরিত হয় (2 ^ -4 থেকে 2 ^ -2 থেকে) তবে সংখ্যাটি অন্যথায় অপরিবর্তিত, তাই 4*0.1 == 0.4

যাইহোক, আপনি 3 দ্বারা গুণ করলে, 0x0.99 এবং 0x0.a0 (0x0.07) এর মধ্যে সামান্য ক্ষুদ্রতর পার্থক্য 0x0.15 ত্রুটিতে রূপান্তর করে, যা শেষ অবস্থানে এক-অঙ্কের ত্রুটি হিসাবে প্রদর্শিত হয়। এটি ০.০ এর বৃত্তাকার মানের তুলনায় 0.1 * 3কে কিছুটা বড় করে তোলে ।

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


25
এটি একটি আশ্চর্যজনকভাবে উত্তর, ধন্যবাদ। (বিশেষত, দেখানোর জন্য ধন্যবাদ .hex(); আমি জানতাম না যে এর অস্তিত্ব ছিল))
এনপিই

21
@ সুপের্যাট: পাইথন সংক্ষিপ্ততম স্ট্রিংটি সন্ধান করার চেষ্টা করে যা কাঙ্ক্ষিত মানের সাথে মিলিত হয় , যাই হোক না কেন ঘটুক। স্পষ্টতই মূল্যায়িত মানটি 0.5ulp এর মধ্যে হওয়া আবশ্যক (বা এটি অন্য কোনও কিছুর সাথে মিলিত হবে) তবে এটি অস্পষ্ট ক্ষেত্রে আরও বেশি সংখ্যার প্রয়োজন হতে পারে। কোডটি অত্যন্ত জঘন্য, তবে আপনি যদি একটি উঁকি নিতে চান: hg.python.org/cpython/file/03f2c8fc24ea/Python/dtoa.c#l2345
nneonneo

2
@ সুপের্যাট: সর্বদা সংক্ষিপ্ততম স্ট্রিং যা 0.5 স্তরের মধ্যে থাকে। ( স্ট্রিক্টলি মধ্যে আমরা বিজোড় lsb একটি float দিকে তাকিয়ে করছি; অর্থাত, সবচেয়ে কম স্ট্রিং এটা রাউন্ড-বন্ধন-টু-ইভেন সঙ্গে কাজ করে তোলে)। এটির ব্যতিক্রমগুলি একটি বাগ এবং তা রিপোর্ট করা উচিত।
মার্ক ডিকিনসন

7
@ মার্করানসাম অবশ্যই তারা এর বাইরে অন্য কিছু ব্যবহার করেছে eকারণ এটি ইতিমধ্যে একটি হেক্স ডিজিট। হয়তো pজন্য ক্ষমতা পরিবর্তে এক্সপোনেন্ট
বার্গি

11
@ বার্গি: pএই প্রসঙ্গে ব্যবহারের ব্যবহারটি কমপক্ষে (কমপক্ষে) C99 এ ফিরে যায় এবং আইইইইই 754 এবং অন্যান্য বিভিন্ন ভাষাতে (জাভা সহ) প্রদর্শিত হয়। কখন float.hexএবং float.fromhexপ্রয়োগ করা হয়েছিল (আমার দ্বারা :-) দ্বারা, পাইথন তখন প্রতিষ্ঠিত অনুশীলনের দ্বারা কেবল যা ছিল তা অনুলিপি করছিল। উদ্দেশ্যটি "পাওয়ার" এর জন্য 'পি' ছিল কিনা তা আমি জানি না, তবে এটি সম্পর্কে ভাবার মতো দুর্দান্ত উপায় বলে মনে হচ্ছে।
মার্ক ডিকিনসন

75

repr(এবং strপাইথন 3 এ) মানটিকে দ্ব্যর্থহীন করতে প্রয়োজনীয় হিসাবে যতগুলি সংখ্যা বের করে দেবে। এই ক্ষেত্রে 3*0.1গুণটির ফলাফলটি হেক্সের ০.০ (0x1.33333333333333333p-2) এর নিকটতম মান নয়, এটি আসলে একটি এলএসবি উচ্চতর (0x1.333333333333334p-2) তাই এটি 0.3 থেকে আলাদা করার জন্য আরও সংখ্যার প্রয়োজন।

অন্যদিকে, গুণ 4*0.1 করে , 0.4 (0x1.999999999999ap-2 হেক্স মধ্যে) নিকটস্থ মান পেতে তাই এটা কোন অতিরিক্ত ডিজিট দরকার নেই।

আপনি এটি বেশ সহজে যাচাই করতে পারেন:

>>> 3*0.1 == 0.3
False
>>> 4*0.1 == 0.4
True

আমি উপরে হেক্স নোটেশনটি ব্যবহার করেছি কারণ এটি দুর্দান্ত এবং কমপ্যাক্ট এবং দুটি মানের মধ্যে কিছুটা পার্থক্য দেখায়। উদাহরণস্বরূপ আপনি নিজে এটি করতে পারেন (3*0.1).hex()। আপনি যদি তাদের পরিবর্তিত সমস্ত দশমিক গৌরবতে দেখতে চান তবে আপনি এখানে যান:

>>> Decimal(3*0.1)
Decimal('0.3000000000000000444089209850062616169452667236328125')
>>> Decimal(0.3)
Decimal('0.299999999999999988897769753748434595763683319091796875')
>>> Decimal(4*0.1)
Decimal('0.40000000000000002220446049250313080847263336181640625')
>>> Decimal(0.4)
Decimal('0.40000000000000002220446049250313080847263336181640625')

2
(+1) ভাল উত্তর, ধন্যবাদ। আপনি কী মনে করেন 3*0.1 == 0.3এবং এর ফলাফলকে অন্তর্ভুক্ত করে এটি "নিকটতম মান নয়" পয়েন্টটি বর্ণনা করার মতো হতে পারে 4*0.1 == 0.4?
এনপিই

পরামর্শের জন্য ধন্যবাদ @ এনপিই আমার ঠিক গেটের বাইরে করা উচিত ছিল।
মার্ক

আমি আশ্চর্য হয়েছি যে এটি যদি খুব কাছের "ডাবলস" এর 0.1, 0.3 এবং 0.4 পর্যন্ত সুনির্দিষ্ট দশমিক মানগুলি মূল্যবান বলে মনে হয়, কারণ প্রচুর লোক ভাসমান-পয়েন্ট হেক্স পড়তে পারে না।
সুপারক্যাট

@ শুক্র্যাট আপনি একটি ভাল পয়েন্ট করেছেন। সেই দুর্দান্ত বড় ডাবলগুলিকে পাঠ্যে লাগানো বিভ্রান্তিকর হবে তবে আমি সেগুলি যুক্ত করার কোনও উপায় ভেবেছিলাম।
মার্ক

25

অন্যান্য উত্তর থেকে এখানে সরলীকৃত উপসংহার।

যদি আপনি পাইথনের কমান্ড লাইনে কোনও ফ্লোট পরীক্ষা করেন বা এটি মুদ্রণ করেন তবে এটি ফাংশনটির মধ্য দিয়ে যায় reprযা এর স্ট্রিং উপস্থাপনা তৈরি করে।

সংস্করণ 3.2 থেকে শুরু করে, পাইথন এর strএবং reprএকটি জটিল রাউন্ডইং প্রকল্প, যা সম্ভব হলে সুন্দর দশমিক কিন্তু বেশি ব্যবহার করে ডিজিটের যেখানে গ্যারান্টি bijective (এক-এক) ভাসে এবং তাদের স্ট্রিং উপস্থাপনা মধ্যে ম্যাপিং করার জন্য প্রয়োজনীয় পছন্দ ব্যবহার করুন।

এই স্কিমটি repr(float(s))সাধারণ দশমিকের জন্য যে চেহারাটির মানটিকে দুর্দান্ত দেখায় তার গ্যারান্টি দেয় , এমনকি যদি তাদের যথাযথভাবে ভাসমান হিসাবে উপস্থাপন করা যায় না (যেমন, যখন s = "0.1")

একই সাথে এটি float(repr(x)) == xপ্রতিটি ভাসমানের জন্য গ্যারান্টি দেয়x


2
আপনার উত্তর পাইথন সংস্করণ> = 3.2 এর জন্য সঠিক, যেখানে strএবং reprভাসমানগুলির জন্য অভিন্ন। পাইথন ২.7-এর জন্য, reprআপনার চিহ্নিত বৈশিষ্ট্য রয়েছে তবে strএটি আরও সহজ - এটি 12 টি গুরুত্বপূর্ণ সংখ্যা গণনা করে এবং এর উপর ভিত্তি করে একটি আউটপুট স্ট্রিং উত্পাদন করে। পাইথনের জন্য <= 2.6, উভয়ই reprএবং strউল্লেখযোগ্য অঙ্কের একটি নির্দিষ্ট সংখ্যার উপর ভিত্তি করে (17 এর জন্য repr, 12 টি str)। (এবং পাইথন ৩.০ বা পাইথন ৩.১ :-) সম্পর্কে কেউ চিন্তা করে না
মার্ক ডিকিনসন

ধন্যবাদ @ মার্কডিকিনসন! আমি উত্তরে আপনার মন্তব্য অন্তর্ভুক্ত।
আইভর

2
নোট করুন যে শেল থেকে গোলাকারটি reprপাইথন ২.7 এর আচরণটি অভিন্ন হবে ...
অ্যান্টি হাপাল

5

পাইথনের প্রয়োগের জন্য সত্যই সুনির্দিষ্ট নয় তবে দশমিক স্ট্রিং ফাংশনে কোনও ফ্লোটে প্রয়োগ করা উচিত।

একটি ভাসমান পয়েন্ট সংখ্যাটি মূলত একটি বাইনারি সংখ্যা, তবে বৈজ্ঞানিক স্বরলিপিতে উল্লেখযোগ্য ব্যক্তির একটি নির্দিষ্ট সীমা থাকে।

বেসের সাথে ভাগ না করা এমন একটি মৌলিক সংখ্যা ফ্যাক্টর রয়েছে এমন কোনও সংখ্যার বিপরীতে সর্বদা একটি পুনরাবৃত্তি ডট পয়েন্ট উপস্থাপনার ফলস্বরূপ। উদাহরণস্বরূপ 1/7 এর একটি প্রধান উপাদান রয়েছে, 7, যা 10 এর সাথে ভাগ করা হয় না এবং এর ফলে বারবারে দশমিক প্রতিনিধিত্ব হয় এবং একই ঘটনাটি 10/10-এ মূল কারণগুলি 2 এবং 5 এর সাথে ভাগ করে নেওয়া হয় না ; এর অর্থ এই যে 0.1 ডট পয়েন্টের পরে সীমাবদ্ধ বিট দ্বারা সঠিকভাবে প্রকাশ করা যায় না।

যেহেতু ০.১ এর কোনও সঠিক উপস্থাপনা নেই, একটি ফাংশন যা প্রতীককে দশমিক পয়েন্ট স্ট্রিংয়ে রূপান্তরিত করে সাধারণত কিছু নির্দিষ্ট মানগুলিকে আনুমানিক করার চেষ্টা করবে যাতে তারা 0.1000000000004121 এর মতো অনাকাঙ্ক্ষিত ফলাফল না পায়।

যেহেতু ভাসমান বিন্দু বৈজ্ঞানিক স্বরলিপিতে থাকে তাই বেসের শক্তির দ্বারা যে কোনও গুণগুলি কেবল সংখ্যার ঘনিষ্ঠ অংশকে প্রভাবিত করে। দশমিক স্বরলিপির জন্য উদাহরণস্বরূপ 1.231e + 2 * 100 = 1.231e + 4, এবং একইভাবে, বাইনারি স্বরলিপিতে 1.00101010e11 * 100 = 1.00101010e101। যদি আমি বেসের একটি শক্তি না দিয়ে গুণ করি তবে উল্লেখযোগ্য সংখ্যাগুলিও প্রভাবিত হবে। উদাহরণস্বরূপ 1.2e1 * 3 = 3.6e1

ব্যবহৃত অ্যালগরিদমের উপর নির্ভর করে, এটি কেবলমাত্র উল্লেখযোগ্য পরিসংখ্যানের ভিত্তিতে সাধারণ দশমিকের অনুমান করার চেষ্টা করতে পারে। ০.০ এবং ০.৪ উভয়েরই বাইনারিতে একই তাৎপর্যপূর্ণ চিত্র রয়েছে, কারণ তাদের ভাসমানগুলি যথাক্রমে যথাক্রমে (8/5) (2 ^ -4) এবং (8/5) (2 ^ -6) কেটে নেওয়া হয়। যদি অ্যালগরিদম 8/5 সিগফিগ প্যাটার্নকে দশমিক 1.6 হিসাবে চিহ্নিত করে, তবে এটি 0.1, 0.2, 0.4, 0.8 ইত্যাদিতে কাজ করবে etc. এটিতে অন্য সংমিশ্রণের জন্য ম্যাজিক সিগফিগ ধরণ থাকতে পারে যেমন ফ্লোট 10 দ্বারা বিভক্ত ফ্লোট 3 এবং অন্যান্য যাদু নিদর্শনগুলি 10 দ্বারা বিভাগ দ্বারা সংস্থাগুলি গঠনের সম্ভাবনা রয়েছে।

3 * 0.1 এর ক্ষেত্রে শেষ কয়েকটি উল্লেখযোগ্য পরিসংখ্যান সম্ভবত ফ্লোট 10 দ্বারা 3 টি বিভাজক থেকে পৃথক হবে, যার ফলে অ্যালগরিদম যথাযথ ক্ষতির জন্য সহনশীলতার উপর নির্ভর করে 0.3 ধ্রুবকের জন্য যাদু সংখ্যাটি সনাক্ত করতে ব্যর্থ হয়।

সম্পাদনা করুন: https://docs.python.org/3.1/tutorial/floatingPoint.html

মজার বিষয় হল, অনেকগুলি বিভিন্ন দশমিক সংখ্যা রয়েছে যা একই নিকটতম আনুমানিক বাইনারি ভগ্নাংশ ভাগ করে। উদাহরণস্বরূপ, 0.1 এবং 0.1000000000000000001 এবং 0.1000000000000000055511151231257827021181583404541015625 সবগুলিই প্রায় 3602879701896397/2 ** 55 দ্বারা সংযুক্ত করা হয়েছে। যেহেতু এই দশমিক মানগুলি একই সান্নিধ্যে ভাগ করে চলেছে (ততক্ষণে যেকোন একটি এক্সট্রিশেন্ট পূর্ববর্তী প্রদর্শিত হবে) (এক্সটারেন্ট পূর্ববর্তী অবস্থায় প্রদর্শিত হবে) ) == এক্স

নির্ভুল ক্ষতির জন্য সহিষ্ণুতা নেই, যদি ফ্লোট এক্স (০.০) ভাসা y (0.1 * 3) এর ঠিক সমান হয় না, তবে repr (x) repr (y) এর ঠিক সমান নয়।


4
এটি বিদ্যমান উত্তরগুলিতে সত্যিই বেশি যোগ করে না।
এন্টি হাপালা

1
"ব্যবহৃত অ্যালগরিদমের উপর নির্ভর করে, এটি কেবলমাত্র উল্লেখযোগ্য পরিসংখ্যানের ভিত্তিতে সাধারণ দশমিকের অনুমান করার চেষ্টা করতে পারে।" <- এটিকে খাঁটি জল্পনা বলে মনে হচ্ছে। অন্যান্য উত্তর পাইথন আসলে কী করে তা বর্ণনা করেছে ।
মার্ক ডিকিনসন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.