💻 آخرین فرصت یادگیری برنامه‌نویسی با آفر ویژه قبل از افزایش قیمت در ۱۵ آذر ماه (🎁 به همراه یک هدیه ارزشمند )
۰ ثانیه
۰ دقیقه
۰ ساعت
۱ ali
یک باگ رایج در پایتون و اینکه این باگ چرا توی C نیست
جامعه پایتون (وب) ایجاد شده در ۰۸ شهریور ۱۴۰۳

یکی از خطا‌های معروف به دلیل ذخیره سازی داده خیلی اوقات توی زبان‌ها اتفاق می‌افته . خطای ROUND OFF  هستش . 
برای پایتون مثلا این مثال رو من دیدم خیلی می‌زنند . که عبارت ( 0.2 + 0.1 == 0.3 ) در پایتون FALSE میشه چون پایتون حاصل جمع 

سمت راست رو به صورت float و برابر عدد 3.0000004  میگیره علاوه بر از اینکه نمی‌دونم یک عدد اعشاری چشکلی به صورت بیت در حافظه ذخیره میشه ؟ ( مثلا شاید به صورت تقسیم دو عدد یا نه صرفا همون ارقام دارن ذخیره میشن ( سوال اول ) 
سوال دومم اینه که چرا این باگ عموما توی زبان CPP جای نداره ! ( سوام دوم ) 



پ.ن : آموزش‌های دیگه پایتون می‌گفتن باید از تابع isclose داخل کتابخونه math استفاده کنم برای مقایسه که با یه درصد خطایی قابل پذیرش باشه ! هر چند اونم به نظرم دستی منطقی‌تر باشه . یعنی خود یکم بالا و پایین و عدد رو به عنوان شرط بذاریم . 

سلام،

این موضوع توو تمام زبان‌های برنامه نویسی که با اعداد اعشاری سروکار دارن اتفاق میوفته.

ماجرای اصلی اینه که کامپیوترها وقتی می‌خوان اعداد اعشاری رو توی حافظه ذخیره کنن، همیشه نمی‌تونن اون‌ها رو به صورت دقیق و بدون خطا ذخیره کنن. به این خاطر که کامپیوترها همه چی رو به صورت بیت (0 و 1) ذخیره می‌کنن و نمایش اعداد اعشاری به صورت دقیق توی این فرم ممکن نیست.

برای مثال، عدد 0.1 توی سیستم دودویی (باینری) به یه دنباله طولانی از اعداد تبدیل می‌شه که کامپیوتر نمی‌تونه به طور کامل ذخیره‌ش کنه. پس مجبور می‌شه که این عدد رو گرد کنه و یه مقدار تقریباً نزدیک به 0.1 رو ذخیره کنه. همین اتفاق برای 0.2 هم می‌افته. حالا وقتی این دو تا عدد رو با هم جمع می‌کنی، نتیجه دقیقاً 0.3 نمی‌شه، بلکه یه چیزی خیلی نزدیک به 0.3 می‌شه که با 0.3 دقیق تفاوت داره. برای همین، وقتی توی پایتون می‌نویسی (0.2 + 0.1 == 0.3)، نتیجه False می‌شه چون این دو تا عدد از نظر کامپیوتر دقیقاً برابر نیستن.

حالا چرا این مشکل توی C++ کمتر دیده می‌شه؟

حالا بریم سراغ سوال دوم. این مشکل توی C++ هم ممکنه اتفاق بیفته، اما نکته اینه که توی C++ معمولاً برنامه‌نویسا خودشون باید دقت اعداد اعشاری رو کنترل کنن و معمولاً از انواع داده‌های دقیق‌تری مثل double استفاده می‌کنن که دقت بیشتری دارن. ولی بازم این به این معنی نیست که C++ کاملاً از این مشکل مصون باشه. در واقع، تفاوت اصلی اینه که برنامه‌نویسا توی C++ بیشتر به این مسئله دقت می‌کنن و روش‌های خاصی برای مدیریت این مشکل دارن.

پس چه کار باید کرد؟

توی پایتون، اگه بخوای از این مشکل دوری کنی، می‌تونی از تابع isclose توی کتابخونه math استفاده کنی که بهت اجازه می‌ده با یه درصد خطای قابل قبول اعداد رو مقایسه کنی. این کار بهت کمک می‌کنه که از خطای گرد کردن جلوگیری کنی. مثلاً:

import math
print(math.isclose(0.2 + 0.1, 0.3))  # True

البته، راه دیگه هم اینه که خودت یه مقدار خطا تعیین کنی و بررسی کنی که آیا اختلاف بین این دو عدد کوچیک‌تر از اون مقدار خطا هست یا نه. مثلاً:

epsilon = 1e-9
print(abs((0.2 + 0.1) - 0.3) < epsilon)  # True

این دو راه می‌تونن بهت کمک کنن که مشکلات ناشی از گرد شدن اعداد اعشاری رو دور بزنی و محاسباتت رو با دقت بیشتری انجام بدی.

محسن موحد ۱۰ شهریور ۱۴۰۳، ۰۰:۱۶