چکیده
در مورد الگوریتم ماشین حساب ما استفاده از یک بافر برای گرفتن عبارت بطور کامل و سپس تجزیه کردن اجزای (Parse) آن از لحاظ فنی غیر ممکن نیست و تنها بدلیل صورت مسئله قادر به انجام آن نیستیم. اما تصور کنید که اگر قرار بود مرورگرهای وب (Web Browsers) ابتدا تمام محتوای یک صفحه را بخواندند و سپس آن را تجزیه کرده و نمایش دهند چه مقدار زمان کاربر و سرویس دهنده وب به هدر می‌رفت و ترافیک بیهوده‌ای برروی خطوط ارتباطی حاصل می‌شد (در اکثر موارد ما با دیدن تنها چند خط از یک صفحه به صفحه دیگری می‌رویم(.

مقدمه
یک الگوریتم مجوعه‌ی متناهی از دستورالعمل های خوش تعریف برای انجام یک عمل است که با داشتن یک حالت اولیه به حالت پایانی مشخص و متناظری خواهد رسید. (با استدلالی ( heuristic )مقایسه شود(

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

 

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

در بعضی کشورها، مثل امریکا، اگر تعبیه فیزیکی الگوریتم ها ممکن باشد ممکن است آن ها به شدت انحصاری شود (برای مثال، یک الگوریتم ضرب ممکن است در واحد محاسبه ی یک ریز پردازنده تعبیه شود (

 

________________________________________
الگوریتم های رسمی شده(formalized algorithms )
الگوریتم ها به خاطر روش پردازش اطلاعات توسط کامپیوتر اساسی و حیاتی هستند، چون یک برنامه کامپیوتری اساساً یک الگوریتم است که به کامپیوتر می گوید برای انجام یک عمل خاص مثل محاسبه حقوق کارمندان و یا چاپ ورقه گزارش دانش آموزان،چه مراحل خاصی را (با چه نظم خاصی) اجرا کند،.به این صورت، یک الگوریتم را می توان هر دنباله از دستوراتی که قابل اجرا توسط یک Turing complete باشد به حساب آورد.به طور نمونه ای هنگامی که الگوریتم کار پرازش اطلاعات را انجام می دهد،

 

داده از طریق یک وسیله یا منبع ورودی گرفته، به یک وسیله خروجی یاsink نوشته و / یا برای استفاده در زمانی دیگر ذخیره می شود. داده ذخیره شده به عنوان بخشی از حالت درونی(internal state) نهاد مجری الگوریتم تلقی می گردد.برای اعمال محاسباتی از این قبیل، الگوریتم باید به دقت تعریف شود :یعنی طوری مشخص شود که برای حالت مختلف محتمل معتبر باشد. یعنی تمام مراحل شرطی باید به طور سیستماتیک بررسی شود ; حالت به حالت.ضابطه مربوط به هر حالت باید واضح (و محاسبه پذیر باشد(.چون الگوریتم ها لیست دقیقی از گام های دقیق است، نظم محاسبه تقریباً همیشه برای کار کرد الگوریتم اساسی می باشد. همواره فرض می شود دستور ها روشن هستند،

 

و گفته می شود از” بالا آغاز” و”تا پایین کشیده می شوند”، اندیشه ای که به طور رسمی تر توسط جریان کنترل توصیف می شود.تا اینجا ی بحث، رسمی سازی قواعد و قوانین برنامه نویسی امری(imperative programming) را به خود گرفت. این عام ترین مفهوم است، و تلاش دارد با وسایل “مکانیکی” مجزا کاری را توصیف کند؛ عملیات تخصیص، تعیین مقدار یک متغیر، برای این مفهوم از الگوریتم رسمی شده یکتا می باشد .در زیر مثالی از این تخصیص آمده است.برای مفاهیم فرعی ) (alternative تشکیل دهنده یک الگوریتم برنامه نویسی تابعی و برنامه نویسی منطقی را ببینید.
ماشین حساب (آشنایی با Syntax Diagram(

________________________________________
الگوریتم ماشین حسابی با تعریف زیر را بنویسید:
• انجام چهار عمل اصلی با اولویت محاسباتی عملگرها طبق آنچه در زیر مشخص شده است:
کد:
+ – عملگر یگانی (Unary)
* /
+ – عملگر دودویی (Binary)
• عبارات داخل پرانتز از اولویت بالاتری برخوردارند.
• اعداد می‌توانند صحیح یا اعشاری باشند.
• پایان هر عبارت با علامت سوال (=) مشخص می‌شود.
• خروج از ماشین حساب با ورود حرف ایکس (X) مشخص می‌شود.

 

مثال:
کد:
۲ * ۳ + ۴ * ۵ =
۲۶

۲ * (۳ + ۴) * ۵ =
۷۰

۲ * ۳ + -۴ * ۵ =
-۱۴

۸٫۱ / -۲٫۵ =
-۳٫۲۴

X
شرایط الگوریتم:
• برای گرفتن عبارت مورد محاسبه از کاربر٬ تنها یک تابع به نام GetChar وجود دارد که در هر زمان تنها یک کاراکتر از کاربر گرفته و آن را برمی‌گرداند.
• به جز آخرین کاراکتر وارد شده توسط کاربر٬ الگوریتم نباید کاراکترهای قبلی وارد شده توسط کاربر را در متغیری ذخیره کند.
• الگوریتم ارائه شده باید بر روی هر ماشین٬ سیستم عامل و زبان برنامه‌نویسی قابل پیاده‌سازی باشد.

 

در مورد الگوریتم ماشین حساب ما استفاده از یک بافر برای گرفتن عبارت بطور کامل و سپس تجزیه کردن اجزای (Parse) آن از لحاظ فنی غیر ممکن نیست و تنها بدلیل صورت مسئله قادر به انجام آن نیستیم. اما تصور کنید که اگر قرار بود مرورگرهای وب (Web Browsers) ابتدا تمام محتوای یک صفحه را بخواندند و سپس آن را تجزیه کرده و نمایش دهند چه مقدار زمان کاربر و سرویس دهنده وب به هدر می‌رفت و ترافیک بیهوده‌ای برروی خطوط ارتباطی حاصل می‌شد (در اکثر موارد ما با دیدن تنها چند خط از یک صفحه به صفحه دیگری می‌رویم(.

 

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

 

در مواردی که ورودی ما از الگوی خاصی (Syntax) تبعیت می‌کند٬ به منظور یافتن الگوریتم مناسب برای تجزیه اجزا (Parse) و تفسیر معنای (Semantics) هر جزء از Syntax Diagram استفاده می‌شود.

همانند فلوچارت که می‌تواند برای نوشتن یک الگوریتم بکار ‌رود٬ Syntax Diagram هم روشی دیگر برای نوشتن یک الگوریتم است.

حال به یافتن الگوریتم ماشین حساب می‌پردازیم تا در این مثال به چگونگی استفاده از Syntax Diagram آشنا شوید.

 

 

برای ساده کردن عبارات از دوران ابتدایی آموخته‌ایم که:
۱٫ هر عبارت داخل پرانتز خود می‌تواند به عنوان عبارتی مستقل محاسبه شده و در نهایت بصورت یک عدد در عبارت اولیه جایگزین شود.
۲٫ علامتهای مثبت و منفی همواره پیش از یک عدد یا یک پرانتز قرار دارند (عملگرهای یگانی(
۳٫ حاصل ضرب و تقسیم تمام اعدادی که با عملگرهای ضرب و تقسیم به هم مرتبط هستند بدون نیاز به اولویت‌بندی قابل محاسبه بوده و حاصل می‌تواند در عبارت اولیه جایگزین گردد (عملگرهای ضرب و تقسیم(

 

۴٫ حاصل جمع و تفریق تمام اعدادی که مابین عملگرهای جمع و تفریق قرار دارند بدون نیاز به اولویت‌بندی قابل محاسبه هستند و حاصل می‌تواند در عبارت اولیه جایگزین گردد (عملگرهای جمع و تفریق دودویی(
با این معلومات و با شروع از کلیات تا رسیدن به جزئیات (Top-Down Design) اقدام به طراحی الگوریتم می‌کنیم.

 

 

ماشین حساب:

ورودی می‌تواند حرف X باشد که در این صورت خارج می‌شویم یا یک عبارت و به دنبال آن علامت تساوی (=) که در این صورت دوباره از اول کار شروع می‌کنیم.

عبارت:

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

جمله:

یک جمله تشکیل شده است از یک ضریب یا حاصل ضرب یا تقسیم دو یا چند ضریب.

ضریب:

یک ضریب می‌تواند در ابتدا یکی از علامتهای مثبت یا منفی باشد و سپس، یا یک عدد یا یک عبارت داخل پرانتز (عبارت تعریفی است بازگشتی).

عدد:

یک عدد تشکیل شده است از یک نقطه (.) و سپس یک یا چند رقم، یا تنها یک یا چند رقم٬ یا یک یا چند رقم و سپس یک نقطه (.) و پس از آن یک یا چند رقم.

رقم:

یک رقم یکی از حروف ۰ تا ۹ است.

خوب الگوریتم ما به همین سادگی نوشته شد. در هر مرحله٬ هرگاه ورودی با آنچه که در Syntax Diagram مربوطه انتظارش را داریم نخواند به معنی این است که عبارت مورد محاسبه نادرست وارد شده است.در بالا برای ساده کردن Syntax Diagram ها فاصله‌ها را ندید گرفته‌ام ولی همانجور که پیداست به غیر از داخل یک عدد٬ در بقیه موارد لازم است که فاصله‌ها را ندید بگیریم.

 

برای ایم منظور با استفاده از تابع GetChar که در صورت مسئله عنوان شده است٬ تابع دیگری می‌نویسیم که در آن بر حسب پارامتر تابع بتوانیم فاصله‌ها را رد کنیم. جدا از آن این تابع آخرین حرف خوانده شده را در داخل یک متغیر که توسط همه توابع قابل دسترسی است ذخیره می‌کند.
کد:
var
C: Char;

const
BlankChars = [‘ ‘, #9, #10, #13];

procedure FetchNextChar(SkipBlanks: Boolean);
begin
repeat
C := GetChar;
until not (SkipBlanks and (C in BlankChars));
end;
و بدنبال توابع مربوط به هر Syntax Diagram نوشته شده است. هر تابع در صورت برخورد با خطا مقدار False را برمی‌گرداند٬ والا مقدار برگشتی True است.

ماشین حساب:

کد:
procedure Calculator;
var
Value: Double;
begin
Writeln(‘Enter an expression or X to exit:’);
FetchNextChar(True);
while C <> ‘X’ do
begin
if GetExpression(Value) and (C = ‘=’) then
Writeln(Value)
else
begin
Writeln(‘Illegal expression!’);
while C <> ‘=’ do { ignores the rest of the illegal expression }
FetchNextChar(True);
end;
Writeln;
Writeln(‘Enter an expression or X to exit:’);
FetchNextChar(True);
end;
end;
عبارت:

کد:
function GetExpression(var Expr: Double): Boolean;
var
NextTerm: Double;
Op: Char;
begin
Result := False;
if GetTerm(Expr) then
begin
Result := True;
while Result and (C in [‘+’, ‘-‘]) do
begin
Op := C;
FetchNextChar(True);
Result := False;
if GetTerm(NextTerm) then
begin
case Op of
‘+’: Expr := Expr + NextTerm;
‘-‘: Expr := Expr – NextTerm;
end;
Result := True;
end;
end;
end;
end;
جمله:

کد:
function GetTerm(var Term: Double): Boolean;
var
NextFactor: Double;
Op: Char;
begin
Result := False;
if GetFactor(Term) then
begin
Result := True;
while Result and (C in [‘*’, ‘/’]) do
begin
Op := C;
FetchNextChar(True);
Result := False;
if GetFactor(NextFactor) then
begin
if Op = ‘*’ then
begin
Term := Term * NextFactor;
Result := True;
end
else if NextFactor <> 0 then
begin
Term := Term / NextFactor;
Result := True;
end;
end;
end;
end;
end;
ضریب:

کد:
function GetFactor(var Factor: Double): Boolean;
var
Negate: Boolean;
begin
Result := False;
Negate := False;
if C in [‘+’, ‘-‘] then
begin
if C = ‘-‘ then
Negate := True;
FetchNextChar(True);
end;
if C = ‘(‘ then
begin
FetchNextChar(True);
if GetExpression(Factor) and (C = ‘)’) then
begin
FetchNextChar(True);
Result := True;
end;
end
else if GetNumber(Factor) then
Result := True;
if Negate then
Factor := -Factor;
end;
عدد:

کد:
function GetNumber(var Number: Double): Boolean;
var
Digit: Integer;
Fraction: Double;
PointPos, P: Integer;
begin
Result := False;
Number := 0;
while GetDigit(Digit) do
begin
Number := Number * 10 + Digit;
FetchNextChar(False);
Result := True;
end;
if C = ‘.’ then
begin
FetchNextChar(False);
PointPos := 0;
while GetDigit(Digit) do
begin
Fraction := Digit;
Inc(PointPos);
for P := 1 to PointPos do
Fraction := Fraction / 10;
Number := Number + Fraction;
FetchNextChar(False);
Result := True;
end;
end;
if C in BlankChars then
FetchNextChar(True);
end;
رقم:

کد:
function GetDigit(var Digit: Integer): Boolean;
begin
Result := False;
if C in [‘0’..’9′] then
begin
Digit := Ord(C) – Ord(‘0’);
Result := True;
end;
end;
برای تمرین سعی کنید با استفاده از Syntax Diagram عملگری برای به توان رساندن و چند تابع ریاضی (مثل Sin و Cos و …) به ماشین حساب اضافه کنید.