قدرت و کارایی عالی خط فرمان در گنو/لینوکس (4)

از قضا در این پست هم به بررسی یک برنامهء خط فرمان میپردازیم.
اسم این برنامه bc هست و چنانچه در سیستم شما نصب شده باشه با همین نام در خط فرمان اجراش کنید. البته بحث ما درمورد پیاده سازی GNU این برنامه هست.

bc’ is a language that supports arbitrary precision numbers with interactive execution of statements. There are some similarities in the syntax to the C programming language. A standard math library is available by command line option. If requested, the math library is defined before processing any files. `bc’ starts by processing code from all the files listed on the command line in the order listed.

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

فایلهایی رو محتوی دستورات نوشته شده با این زبان (که میتونن بسادگی نوشتن جمع و تفریق تا حلقه و شرط و گرفتن ورودی از کاربر باشن) میشه در خط فرمان به این برنامه پاس کرد، در نهایت وارد خط فرمان این برنامه میشیم که در اونجا میتونیم عملیات ساده مثل چهار عمل اصلی، تا عملیاتی پیچیده تر و چند مرحله ای رو انجام بدیم. چنانچه این برنامه رو با آپشن l فراخوانی کرده باشیم یک سری توابع ریاضی استاندارد مثل سینوس و کسینوس و لگاریتم طبیعی و چند تابع دیگه لود شده و در برنامه در دسترس قرار میگیرن.
تا اینجا تنها گفتیم که این برنامه عملیات ریاضی انجام میده و البته یک زبان برنامه نویسی مخصوص و خیلی مختصر (دربرابر زبانهای با کاربرد برنامه نویسی عادی) برای انجام برنامه های مخصوص محاسباتی چند مرحله ای درش تعبیه شده؛ اما نکتهء دیگه ای که ذکرش در اینجا لازم بنظر میرسه اینه که با این برنامه میشه روی اعداد بسیار بزرگ و همچنین با دقت (تعداد ارقام اعشار) بسیار زیاد کار کرد. محاسبات شما میتونن اعداد فوق العاده بزرگ و فوق العاده دقیقی رو تولید کنن.
شما در این برنامه حلقه دارید، شرط، تابع، متغییر (دو نوع معمولی و آرایه)، عملگرهای مقایسه ای و منطقی (البته نتیجه برگردانده شده، بجای true و false، صفر و یک هست)، و یکسری تابعهای مخصوص از پیش تعریف شده و همچنین توابع ریاضی ای که گفتیم با آپشن l در دسترس قرار میگیرن.
ضمنا مقادیر ورودی و خروجی این برنامه میتونن در مبنای تعیین شده توسط شما باشن. حالت پیشفرض، مبنای ۱۰ برای ورودی و خروجی هست.

خب وقت مثال رسیده:

pi=$(echo "scale=10; 4*a(1)" | bc -l)

این مثال از خود منوال هست.
توجه کنید که این فرمان رو در خط فرمان شل نوشتیم و اجرا کردیم، و نه در خط فرمان bc.
کاری که این دستور میکنه اینه که فرامین محاسباتی مناسبی رو که جهت محاسبهء عدد پی با ده رقم اعشار هست به برنامهء bc ارسال میکنه و نتیجهء نهایی در متغییر شل pi قرار میگیره (با دستور echo $pi میتونید مقدارش رو در خط فرمان شل ببینید).
فرامین مورد نظر ارسالی، دو فرمان هستن که با سمیکالن از هم جدا شدن.
فرمان scale=10 به bc میگه که محاسبه با دقت ده رقم اعشار رو میخواد
فرمان بعدی 4*a(1) هست که معناش ضرب ۴ در آرک تانژانت ۱ هست، که عدد پی رو نتیجه میده. توجه کنید که بعلت استفاده از این تابع، bc رو با آپشن l که توابع استاندارد ریاضی رو لود میکنه اجرا میکنه، فراخوانی کردیم.
bc این فرمانها رو اجرا کرده و خروجی خودش رو به خروجی استاندارد که صفحه‌ ترمینال هست میفرسته.
ساختارویژهء شل، یعنی علامت دلار در ابتدای پرانتز باز و بسته، که کل این فرامین رو احاطه کرده، باعث میشه که هر خروجی استاندارد تولید شده در داخل این پرانتزها، بجای کل این ساختار قرار بگیره، مثل اینکه اونجا تایپ شده باشه. با این روش مقدار خروجی bc بجای چاپ شدن، در متغییر pi قرار میگیره. به این ساختار مفید و پرکاربرد شل، Command substitution گفته میشه.
البته فرم دیگر این ساختار (فرم قدیمی اون)، قرار دادن فرامین مورد نظر در علامتهای Back tick هست (`).

خب حالا ما وارد bc میشیم:

[root@localhost ~]# bc -l
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.

و در خط فرمانش، دستوراتی رو اجرا میکنم:

scale
20

مقدار دقت (ارقام اعشار) رو بررسی میکنیم؛ خروجی ۲۰ یعنی تعداد ارقام اعشار ۲۰ است. چون bc رو با آپشن l فراخوانی کردیم دقت اعشاری داریم، ولی بدون این آپشن مقدار پیشفرض برای scale صفر هست. یعنی خروجی نتیجهء بعضی محاسبات (تقسیم) بطور معمول بصورت صحیح هست. بنابراین شما در هنگام استفاده از این برنامه (bc) با پاس کردن فرمانها بهش یا در داخل فایلهای نوشته شده با این زبان که میخواید نتایج اعشاری با دقت دلخواه داشته باشید، باید فرمان scale=x رو بدید، که ایکس تعداد ارقام اعشار مورد نظر شما هست.

scale=50
456/3.3
138.18181818181818181818181818181818181818181818181818

تعداد ارقام اعشار رو ۵۰ قرار میدیم (۲۰ تا کم بود برامون!!)
محاسبهء ۴۵۶ تقسیم بر ۳.۳.
نتیجه رو با ۵۰ رقم اعشار ملاحظه میفرمایید.

scale(456/3.3)
50

تابع ویژهء scale، تعداد ارقام اعشار یک محاسبه یا عدد رو برمیگردونه.

scale(5.54*2.4)
3
scale(5/2)
50
scale(4/2)
50

خواستم بگم اگر از اینطور توابع ویژه استفاده میکنید به این تفاوتهای ظریف توجه داشته باشید. این تابع بسادگی تعداد همون ارقام اعشاری رو که در حالت عادی نمایش داده میشه برمیگردونه، گرچه همه صفر باشن!

2^3000
12302319221611171769315588132767525146407138957368337157661180291600\
58800614672948775360067838593459582429649254051804908512884180898236\
82358508248206534833123495935035584501741302332011136066692262472823\
97568804164344783156936750134130907572086903767932966588106629418244\
93488451726505303712916005346747908623702673480919353936813105736620\
40235274477690384047788365110032240930198348836380293054048248790976\
34840982539407286851320444088637347542712125924717786439494866885117\
21051561970432780747454823776808464180697103083861812184348565522740\
19579668262220551184551208055201031005025580158934964592800113374547\
42207150136834139075427790637598338761013542351842450966700421607206\
29411581502371248008430447184842098610320580417992206662247328722122\
08851364368390767036020916265367064113093699700217050067550137472399\
87660058275793007232534748906122501351718891748990799112915123997738\
72178519018229989376

دو به توان ۳۰۰۰.

length(2^3000)
904

خب، کنجکاو شدیم ببینیم عدد قبلی چند رقمی بوده!
تابع ویژهء length، تعداد ارقام بکار رفته در عدد یا نتیجهء محاسبه ای رو برمیگردونه.

length(5/2)
51

توجه کنید که اگر عدد اعشار داشته باشه، اعداد بعد از اعشار هم به حساب میان؛ نقطهء اعشار شمرده نمیشه.

(2994563.034*((3-5.04)^-10)*sqrt(456))/-.23
-222733.92500476577084326894346580777764319861310198677173

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

define f (x) {
if (x <= 1) return (1);
return (f(x-1) * x);
}
f(100)
93326215443944152681699238856266700490715968264381621468592963895217\
59999322991560894146397615651828625369792082722375825118521091686400\
0000000000000000000000

تعریف تابع فاکتوریل (از نوع بازگشتی)، و محاسبهء مقدار ۱۰۰ فاکتوریل با استفاده از این تابع.
در مثالهای قبلی هم دیدید که خطهای طولانی شکسته میشن و در انتهای خطوط شکسته شده بک اسلش قرار میگیره. البته طول سطرهای خروجی قابل تنظیم هست (با متغییر محیطی (در شل) BC_LINE_LENGTH):

[root@localhost ~]# BC_LINE_LENGTH=25; export BC_LINE_LENGTH; echo '2^1024' | bc
17976931348623159077293\
05190789024733617976978\
94230657273430081157732\
67580550096313270847732\
24075360211201138798713\
93357658789768814416622\
49284743063947412437776\
78934248654852763022196\
01246094119453082952085\
00576883815068234246288\
14739131105408272371633\
50510684586298239947245\
93847971630483535632962\
4224137216

یک مثال برای مشخص کردن چگونگی تعیین طول خطهای خروجی. البته معمولا طول خطوط رو نیاز داریم به دلایل مختلفی افزایش بدیم و نه کاهش، ولی اینجا برای نشان داده شدن مثال، طول خطوط رو کم کردیم.

scale=10
obase=2
456/3.3
10001010.0010111010001011101000101110100010

تعداد ارقام اعشار رو روی ۱۰ قرار میدیم.
مبنای خروجی رو روی ۲ قرار میدیم.
فرمان محاسبهء 456 تقسیم بر 3.3 رو صادر میکنیم.
نتیجه در مبنای ۲ مشاهده میشه.
قابل توجه هست که تعداد ارقام اعشار، در مبنای ده سنجیده میشه و نه مبنای خروجی.

obase=1010
10001010.0010111010001011101000101110100010
138.1818181817652657628059387207031250

مبنای خروجی رو ۱۰ قرار میدیم. توجه کنید که چون مبنای ورودی رو روی ۲ گذاشته بودیم، هر عددی که وارد میکنیم بعنوان عدد مبنای دو دیده میشه و بنابراین ما باید عدد ۱۰ رو هم به مبنای ۲ وارد کنیم. پس همینطور برای تغییر مبنای ورودی هم باید عدد مبنای مورد نظر رو در مبنای فعلی ورودی وارد کرد.
حالا میتونیم ببینیم عدد مبنای ۲ محاسبهء قبلی، در مبنای ۱۰ چی میشه.

obase=10
length(10001010.0010111010001011101000101110100010 )
100101
obase=1010
100101
37

مبنای خروجی رو روی ۲ قرار میدیم.
طول عدد رو مجددا در این حالت بررسی میکنیم.
مبنای خروجی رو مجددا به ۱۰ میبریم.
طول بدست آمده در مبنای ۲ رو وارد کرده و حاصل رو در مبنای ۱۰ دریافت میکنیم.
پس به این نتیجه میرسیم که طول یا درواقع تعداد ارقام هر عدد پاس شده به این تابع، همواره برابر تعداد ارقام اون عدد در مبنای ۱۰ هست (در واقع این عملکرد در تابعهای دیگه هم دیده میشه؛ پس حواستون به این مسئله باشه).

obase=1010
ibase=1010

خب دیگه خسته شدیم! مبناهای ورودی و خروجی رو به ۱۰ برمیگردونیم.

scale=3
2.000000000001*2
4.000000000002
2.0000000000000*1
2.0000000000000

توجه کنید که بعضی حالات مثل این (ضرب)، چنانچه دقت اعداد ورودی ما بیشتر از مقدار scale باشه، دقت مقدار ورودی مورد استفاده قرار میگیره و نه scale.

f=1; for(i=1; i<=10; i++) f*=i; f
3628800

محاسبهء ۱۰ فاکتوریل با استفاده از حلقهء for.

ibase=16
FF
255

نکته: در مبنای ورودی بالاتر از ۱۰ (مبنای ورودی حداکثر تا شانزده امکان داره)، از حروف بزرگ A تا F برای نمایش ارقام بزرگتر از ۹ استفاده کنید.

obase=17
100
05 15

در مبناهای خروجی بالاتر از ۱۶، معادل هر رقم در اون مبنا، در مبنای ۱۰ و در یک ستون مجزا نوشته میشه.
۵ * ۱۷ + ۱۵ = ۱۰۰

خب فکر کنم کافی باشه!
برای اطلاع دقیقتر از این برنامه و زبان مخصوصش و نکات و قابلیتهای کاملش، به منوالش مراجعه کنید.
در خط فرمان info bc، در آدرسبار مرورگر/فایل منیجر کانکرر info:bc یا صورت اختصاری ##bc رو، برای دستیابی به منوال این برنامه میتونید بکار ببرید.

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

*

شما می‌توانید از این دستورات HTML استفاده کنید: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>