.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.45) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Required to disable full justification in groff 1.23.0. .if n .ds AD l .\" ======================================================================== .\" .IX Title "RPNTUTORIAL 1" .TH RPNTUTORIAL 1 2026-08-08 1.11.0 rrdtool .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "نام (NAME)" rpntutorial \- راهنمای خواندن عبارت‌های RPN در RRDtool به قلم Steve Rader .SH "توضیحات (DESCRIPTION)" .IX Header "DESCRIPTION" این راهنما به شما کمک می‌کند تا با عبارت‌های RPN (نشانه‌گذاری معکوس لهستانی) در RRDtool، همان‌طور که در آرگومان‌های CDEF در دستور RRDtool graph دیده می‌شوند، آشنا شوید و بر آن‌ها مسلط گردید. .SH "خواندن عملگرهای مقایسه‌ای (Reading Comparison Operators)" .IX Header "Reading Comparison Operators" عملگرهای منطقی RPN شامل LT، LE، GT، GE و EQ آن‌قدر که به نظر می‌رسند دشوار نیستند. این عملگرها روی دو مقدار پیش از خود در پشته (در سمت چپ) عمل می‌کنند. این دو مقدار پشته را از چپ به راست بخوانید و عملگر را در میان آن‌ها قرار دهید. اگر گزاره‌ی حاصل درست (true) بود، آن سه مقدار را در پشته با «1» جایگزین کنید. اگر گزاره نادرست (false) بود، آن سه مقدار را با «0» جایگزین نمایید. .PP برای نمونه، عبارت «2,1,GT» را در نظر بگیرید. این عبارت RPN را می‌توان به صورت «آیا دو بزرگ‌تر از یک است؟» خواند. پاسخ این پرسش «درست» است. بنابراین این سه مقدار باید با «1» جایگزین شوند. در نتیجه، عبارت RPN به صورت 2,1,GT به 1 ارزیابی می‌شود. .PP حال «2,1,LE» را در نظر بگیرید. این عبارت RPN را می‌توان به صورت «آیا دو کوچک‌تر یا مساوی یک است؟» خواند. پاسخ طبیعی «خیر» است و بنابراین عبارت RPN به صورت 2,1,LE به 0 ارزیابی می‌شود. .SH "خواندن عملگر IF (Reading the IF Operator)" .IX Header "Reading the IF Operator" عملگر منطقی IF در RPN نیز می‌تواند بسیار سرراست باشد. کلید فهم عملگرهای IF این است که درک کنید بخش شرط در نگارش سنتی «if X then Y else Z» (اگر X آنگاه Y وگرنه Z) از *قبل* ارزیابی شده است. بنابراین عملگر IF تنها روی یک مقدار در پشته عمل می‌کند: سومین مقدار در سمت چپ مقدار IF. مقدار دوم در سمت چپ IF مربوط به شاخه درست («Y») است؛ و نخستین مقدار در سمت چپ IF مربوط به شاخه نادرست («Z») است. عبارت RPN به شکل «X,Y,Z,IF» را از چپ به راست به این صورت بخوانید: «if X then Y else Z». .PP برای مثال، «1,10,100,IF» را در نظر بگیرید. این عبارت در نگاه اول شاید عجیب به نظر برسد؛ اما وقتی آن را به صورت «if 1 then 10 else 100» بخوانید کاملاً روشن است: 1 درست است، بنابراین پاسخ 10 خواهد بود. توجه داشته باشید که تنها صفر نادرست (false) است و تمام مقادیر دیگر درست (true) محسوب می‌شوند. عبارت «2,20,200,IF» («if 2 then 20 else 200») به 20 ارزیابی می‌شود، و «0,1,2,IF» («if 0 then 1 else 2») به 2 ارزیابی می‌گردد. .PP دقت کنید که هیچ‌کدام از مثال‌های بالا عبارت کامل «if X then Y else Z» را به‌طور واقعی شبیه‌سازی نمی‌کنند؛ زیرا برنامه‌نویسان رایانه این عبارت را معمولاً به صورت «اگر شرطی برقرار بود آنگاه Y وگرنه Z» می‌خوانند. بنابراین بسیار مهم است که بتوانید عملگرهای IF را در کنار عملگرهای LT، LE، GT، GE و EQ بخوانید و درک کنید. .SH "چند مثال (Some Examples)" .IX Header "Some Examples" اگرچه عبارت‌های مرکب ممکن است بیش از حد پیچیده به نظر برسند، اما می‌توان آن‌ها را بسیار شیک و ساده در نظر گرفت. برای درک سریع عبارت‌های RPN، باید الگوریتم ارزیابی آن‌ها را بدانید: جستجو را از چپ به راست پیمایش کنید تا به یک عملگر برسید. وقتی عملگر پیدا شد، آن را به همراه تعدادی از مقادیر پیش از آن (که طبق تعریف، نباید عملگر باشند) از پشته خارج کنید (pop کنید) و عملگر را روی آن‌ها اعمال نمایید. .PP برای مثال، در پشته‌ی «1,2,3,+,+»، عبارت «2,3,+» در نخستین پیمایش (به عنوان «2+3») ارزیابی شده و با 5 جایگزین می‌شود. نتیجه‌ی این کار پشته‌ی «1,5,+» خواهد بود. سرانجام، «1,5,+» ارزیابی شده و پاسخ 6 به دست می‌آید. برای راحتی کار، نوشتن این مجموعه از عملیات به شکل زیر مفید است: .PP .Vb 3 \& 1) 1,2,3,+,+ eval is 2,3,+ = 5 result is 1,5,+ \& 2) 1,5,+ eval is 1,5,+ = 6 result is 6 \& 3) 6 .Ve .PP بیایید از این شیوه برای حل راحت‌تر چند عبارت پیچیده‌ی RPN با چندین عملگر منطقی استفاده کنیم: .PP .Vb 1 \& 1) 20,10,GT,10,20,IF eval is 20,10,GT = 1 result is 1,10,20,IF .Ve .PP بخش eval را این‌گونه بخوانید: «20 بزرگ‌تر از 10 است» را بردارید (pop کنید)، بنابراین 1 را در پشته قرار دهید (push کنید). .PP .Vb 1 \& 2) 1,10,20,IF eval is 1,10,20,IF = 10 result is 10 .Ve .PP بخوانید: «if 1 then 10 else 20» را بردارید (pop کنید)، پس 10 را در پشته قرار دهید (push کنید). اکنون فقط 10 باقی مانده است، بنابراین 10 پاسخ نهایی است. .PP حال بیایید یک عبارت پیچیده‌ی RPN را بخوانیم که شامل عملگر سنتی ضرب نیز هست: .PP .Vb 4 \& 1) 128,8,*,7000,GT,7000,128,8,*,IF eval 128,8,* result is 1024 \& 2) 1024 ,7000,GT,7000,128,8,*,IF eval 1024,7000,GT result is 0 \& 3) 0, 7000,128,8,*,IF eval 128,8,* result is 1024 \& 4) 0, 7000,1024, IF result is 1024 .Ve .PP اکنون به نخستین مثال با چندین عملگر منطقی بازمی‌گردیم، اما مقدار 20 را با متغیر «input» جایگزین می‌کنیم: .PP .Vb 1 \& 1) input,10,GT,10,input,IF eval is input,10,GT ( lets call this A ) .Ve .PP بخش eval را به صورت «اگر input > 10 باشد آنگاه درست (true)» بخوانید و «input,10,GT» را با «A» جایگزین نمایید: .PP .Vb 1 \& 2) A,10,input,IF eval is A,10,input,IF .Ve .PP بخوانید: «if A then 10 else input». حال A را مجدداً با توصیف کامل آن جایگزین کنید و\-\-ببینید!\-\-توصیفی کاملاً خوانا از این عبارت در اختیار دارید: .PP .Vb 1 \& if input > 10 then 10 else input .Ve .PP در نهایت، بیایید به پیچیده‌ترین مثال اول برگردیم و مقدار 128 را با «input» جایگزین کنیم: .PP .Vb 1 \& 1) input,8,*,7000,GT,7000,input,8,*,IF eval input,8,* result is A .Ve .PP که در آن A برابر است با «input * 8» .PP .Vb 1 \& 2) A,7000,GT,7000,input,8,*,IF eval is A,7000,GT result is B .Ve .PP که در آن B برابر است با «if ((input * 8) > 7000) then true» .PP .Vb 1 \& 3) B,7000,input,8,*,IF eval is input,8,* result is C .Ve .PP که در آن C برابر است با «input * 8» .PP .Vb 1 \& 4) B,7000,C,IF .Ve .PP سرانجام رمزگشایی خوانایی از این عبارت پیچیده‌ی RPN به همراه متغیر در دست داریم: .PP .Vb 1 \& if ((input * 8) > 7000) then 7000 else (input * 8) .Ve .SH "تمرین‌ها (Exercises)" .IX Header "Exercises" تمرین ۱: .PP عبارت‌های «3,2,*,1,+» و «3,2,1,+,*» را به صورت دستی محاسبه کنید. آن‌ها را در نشانه‌گذاری سنتی بازنویسی نمایید. توضیح دهید که چرا این دو پاسخ متفاوتی دارند. .PP پاسخ ۱: .PP .Vb 3 \& 3*2+1 = 7 و 3*(2+1) = 9. این دو عبارت پاسخ‌های \& متفاوتی دارند، زیرا تغییر دادن عملگرهای جمع و ضرب، \& ترتیب ارزیابی آن‌ها را دگرگون می‌کند. .Ve .PP تمرین ۲: .PP ممکن است شخصی وسوسه شود تا عبارت زیر را: .PP .Vb 1 \& input,8,*,56000,GT,56000,input,*,8,IF .Ve .PP با حذف کاربرد تکراری «input,8,*» به شکل زیر کوتاه‌تر کند: .PP .Vb 1 \& input,56000,GT,56000,input,IF,8,* .Ve .PP با استفاده از نشانه‌گذاری سنتی نشان دهید که این دو عبارت یکسان نیستند. عبارتی معادل عبارت اول بنویسید که در آن از عملگرهای LE و DIV استفاده شده باشد. .PP پاسخ ۲: .PP .Vb 2 \& if (input <= 56000/8 ) { input*8 } else { 56000 } \& input,56000,8,DIV,LE,input,8,*,56000,IF .Ve .PP تمرین ۳: .PP به طور خلاصه توضیح دهید که چرا نشانه‌گذاری ریاضی سنتی نیازمند استفاده از پرانتز است. توضیح دهید که چرا نشانه‌گذاری RPN نیازی به پرانتز ندارد. .PP پاسخ ۳: .PP .Vb 6 \& عبارت‌های ریاضی سنتی با انجام ضرب و تقسیم در ابتدا، \& و سپس جمع و تفریق ارزیابی می‌شوند. پرانتزها برای \& تحمیل ارزیابی جمع پیش از ضرب (و مانند آن) استفاده \& می‌شوند. RPN نیازی به پرانتز ندارد، چرا که ترتیب \& قرارگیری اشیاء در پشته می‌تواند ارزیابی جمع پیش از \& ضرب را اجباری کند. .Ve .PP تمرین ۴: .PP توضیح دهید که چرا پیاده‌سازی نشانه‌گذاری RPN به جای نشانه‌گذاری ریاضی سنتی برای توسعه‌دهندگان RRDtool مطلوب‌تر بود. .PP پاسخ ۴: .PP .Vb 5 \& الگوریتمی که نشانه‌گذاری ریاضی سنتی را پیاده‌سازی می‌کند \& پیچیده‌تر از الگوریتم مورد استفاده برای RPN است. از این رو، \& پیاده‌سازی RPN به Tobias Oetiker امکان داد کد کمتری بنویسد! \& (کد برنامه همچنین پیچیدگی کمتری داشته و در نتیجه احتمال \& بروز باگ و خطا در آن کمتر است.) .Ve .SH "نویسندگان (AUTHORS)" .IX Header "AUTHOR" Steve Rader