Mostafa Fallah - مصطفی فلاح
Mostafa Fallah - مصطفی فلاح
خواندن ۳ دقیقه·۴ سال پیش

مساله Floating Numbers در زبانهای برنامه نویسی

مقدار جمع این دو عدد 0.3 نمیشود !
مقدار جمع این دو عدد 0.3 نمیشود !


این یه مساله قدیمی هست که خیلی از برنامه نویسها ممکنه باهاش مواجه شده باشند. قضیه این هست که نتایج عملیات محاسباتی اونها گاهی اشتباه میشه، مخصوصا وقتی از اعداد اعشاری در محاسباتشون استفاده میکنن و در این مواقع با خودشون میگن : یعنی چی؟ چرا شماره های من جمع نمی شه؟ مثلا : 0.1 + 0.2 ، ولی نتیجه این شده : 0.30000000000000004

خب برای این که این مساله رو دقیقا متوجه بشیم، باید به سوالات زیر جواب بدیم :

1 - چرا حاصل جمع اعداد من مانند 0.1 + 0.2 ، 0.3 نمیشود و در عوض من یک نتیجه عجیب مانند 0.3000000000000000004 دریافت می کنم؟

زیرا کامپیوتر ها از فرمتی خاص (binary floating-point) استفاده می کنند که نمی تواند عددی مانند 0.1 ، 0.2 یا 0.3 را به طور دقیق ارائه کند. در واقع هنگامی که کد شما کامپایل یا تفسیر می شود ، مقدار "0.1" شما از قبل به نزدیکترین عدد در آن فرمت (مثلا 0.0999999) گرد شده ،که منجر به یک (خطای گرد شدن) حتی قبل از محاسبه می شود.

فرمت Floating Point : از آنجا که حافظه کامپیوتر محدود است ، صرف نظر از اینکه از کسرهای باینری استفاده می کنید یا از کسر اعشاری ، نمی توانید اعداد را با دقت نامحدود ذخیره کنید: پس در واقع در بعضی مواقع باید بخشی از این عدد را حذف کنید.
خطاهای گرد شدن : از آنجا که اعداد ممیز شناور (floating-point) دارای تعداد محدودی رقم هستند ، نمی توانند تمام اعداد واقعی را به طور دقیق نشان دهند: به عبارتی وقتی تعداد رقم بیشتری از حد مجاز قالب وجود داشته باشد، تعداد باقیمانده حذف می شود و در نتیجه عدد گرد می شود.

2 - چرا کامپیوتر ها از چنین سیستم احمقانه ای استفاده می کنند؟

احمقانه نیست ، فقط متفاوت است. متغیرهای اعشاری نمی توانند عددی مانند 1.3 را به درستی ارائه کنند، بنابراین شما باید مقدار را گرد کنید به مقداری مانند 0.33 ، و شما قطعا انتظار ندارید که حاصل جمع 0.33 + 0.33 + 0.33 + 0.33 ، 1 بشود !!

توضیح تکمیلی اینکه، کامپیوترها از اعداد باینری استفاده می کنند زیرا در برخورد با آنها سریعتر عمل می کنند و از آنجایی که اعدادی که با آنها کار می کنید عموما گرد نیستند، خطای کوچک در رقم اعشاری هفدهم اصلاً مهم نیست.

برای جلوگیری از این مشکل چه کاری می توانم انجام دهم؟

این به نوع محاسبات شما بستگی دارد.

اگر واقعاً برای جمع آوری دقیقاً به نتایج خود احتیاج دارید ، مخصوصاً وقتی با پول کار می کنید: از یک نوع داده اعشاری ویژه استفاده کنید.

اگر فقط نمی خواهید همه آن اعشار اعشاری را ببینید: به سادگی هنگام نمایش نتیجه خود را به تعداد ثابت رقم اعشار گرد کنید.

اگر هیچ نوع داده اعشاری در دسترس ندارید ، یک گزینه جایگزین کار با عدد صحیح است ، به عنوان مثال محاسبات پول را کاملاً در ریال انجام دهید. ا

چرا سایر محاسبات مانند 0.1 + 0.4 به درستی کار می کنند؟

در این صورت ، نتیجه (0.5) را می توان دقیقاً به عنوان یک عدد ممیز شناور نشان داد و این امکان وجود دارد که خطاهای گرد شدن در عددهای ورودی یکدیگر را پوشش دهند - اما لزوماً نمی توان به آن اعتماد کرد (به عنوان مثال وقتی این دو ابتدا اعداد در نمایش های مختلف با اندازه متفاوت بخش شناور ذخیره می شوند ، ممکن است خطاهای گرد شدن یکدیگر را جبران نکنند).

در موارد دیگر مانند 0.1 + 0.3 ، نتیجه در واقع 0.4 نیست ، اما به اندازه کافی به مقدار 0.4 نزدیک است. و در نتیجه بسیاری از زبانها به جای تبدیل نتیجه واقعی به نزدیکترین کسر اعشاری ،خود آن عدد را نمایش می دهند.


منبع این مطلب سایت https://floating-point-gui.de هست که توی همین سایت برای زبانهای سی شارپ، جاوا اسکریپت و ... راه حلهایی برای این مساله گفته شده.


floating numbersاعداد اعشاریزبان‌های برنامه نویسیfloating pointخطای گرد شدن
مدیر پروژه، برنامه نویس، سعی میکنم کتاب هم بخونم
شاید از این پست‌ها خوشتان بیاید