PDA

مشاهده نسخه کامل : خطا های محاسباتی در رایانه



ravegoat
05-05-10, 09:19
در رایانه هایی که از منطق باینری تبعیت می کنند، داده ها از نوع صفر و یک هستند. بنابراین اگر بخواهیم اعداد را برای رایانه تعریف کنیم باید آن ها را به صفر و یک تبدیل کنیم. به عبارتی دیگر باید اعداد را از مبنای 10 به مبنای 2 ببریم. اما آیا می توان هر عددی را از مبنای ده به مبنای دو برد بدون آن که ارزش آن تغییری کند؟
پاسخ این سوال خیر است. عدد 0.31 را در نظر بگیرید. اگر بخواهیم 0.31 را به مبنای دو ببریم به تعداد نا متناهی صفر و یک نیاز داریم (این مسئله با مفاهیم ریاضی قابل اثبات است). هر چه تعداد صفر و یک ها بیش تر باشد، مقدار عدد تولید شده در مبنای دو به 0.31 نزدیک تر می شود ولی هرگز دقیقا" برابر با آن نمی شود. با توجه به این که مقدار کلمه ی حافظه در رایانه ها محدود است (32 یا 64 بیت)، در نتیجه برای تعریف یک عدد ما مجبوریم به تعداد معینی عدد اکتفا کنیم.

چنین مواردی زمینه ساز بروز خطا در ماشین می شوند. به مورد زیر توجه کنید:

در ریاضی عملگر جمع (+) خاصیت جا به جایی دارد مثلا": a+b+c=c+a+b
اما این خاصیت همواره در محاسبات کامپیوتری وجود ندارد:

a ، b و c را این گونه مقدار دهی می کنیم:
a=-0.5
b=0.48
c=0.02

می دانیم در هر حال باید جمع مقادیر a b c برابر صفر شود اما در رایانه:
c+b+a برابر صفر می شود و در مقابل a+b+c برابر:
-1.73472347597681E-17
یعنی تقریبا" -1.7 ضرب در ده به توان -17 . چنین عددی بسیار نزدیک به صفر است اما مساوی صفر نیست. اگر این مقدار کوچک در یک عدد بزرگ ضرب شود نتیجه فاجعه بار خواهد بود.
چنین خطایی هم در برنامه نویسی تحت دات نت وجود دارد و هم در نرم افزار محاسباتی قدرتمندی چون Matlab . اما مقصر هسته ی .Net یا Matlab نیست بلکه این منطق رایانه های امروزی هست که موجب چنین خطایی می شود.

یا Sin(π) را در نظر بگیرد. می دانیم که مقدار این عبارت صفر است اما رايانه آن را عددی نزدیک به صفر محاسبه می کند نه خود صفر. این امر به دلیل نا منتاهی بودن عدد پی رخ می دهد.

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

اما آیا راهی برای کنترل این خطا ها وجود دارد؟
خوشبختانه جواب مثبت است. ما می توانیم با تعریف الگوریتم های ویژه ای، خطا های عملیات جمع و یا ضرب را کنترل کنیم و مقدار آن ها را به حداقل برسانیم.

به عنوان مثال برای عمل جمع می توان از الگویی استفاده کرد که در دوران دبستان با آشنا شدیم. برای این کار اعداد را به صورت رشته (String) وارد می کنیم. سپس کارکتر ها را یک به یک از رشته ها استخراج کرده، آن ها را تبدیل به رقم می نماییم و در نهایت کارکتر هایی را که ارزش مکانی برابر دارند، نظیر به نظیر با هم جمع می کنیم. نمونه ای از این الگوریتم به زبان VB.Net در زیر آورده شده است:





Dim dsd As Decimal
Dim mynum(2) As String
mynum(0) = "-0.50"
mynum(1) = "0.48"
mynum(2) = "0.02"
dsd = 0
dsd += (-Val(mynum(0).Chars(4)) + Val(mynum(1).Chars(3)) + Val(mynum(2).Chars(3))) * 10 ^ -2
dsd += (-Val(mynum(0).Chars(3)) + Val(mynum(1).Chars(2)) + Val(mynum(2).Chars(2))) * 10 ^ -1
dsd += (-Val(mynum(0).Chars(1)) + Val(mynum(1).Chars(0)) + Val(mynum(2).Chars(0)))
MsgBox(dsd)


این روش را نیز می توان به عمل ضرب تعمیم داد. بدین شکل می توانیم چهار عمل اصلی را برای اعداد بسیار بزرگ یا بسیار کوچک پیاده کینم بدون آنکه خطایی داشته باشیم.
برای توابع مثلثاتی نیز می شود از این ترفند استفاده کرد: زمانی که زاویه ی درون سیسنوس مضرب صحیحی از π بود آن گاه می توانیم جواب را تا چند رقم بعد از اعشار (ترجیحا" 15 رقم) گرد کنیم تا بدین شکل خطا کنترل شود.

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