پرسش و پاسخ شماره ۲۲ - آموزش اسکریپت نویسی
X
تبلیغات
رایتل

آموزش اسکریپت نویسی

آموزش اسکریپت نویسی پوسته گنو-لینوکس

#!/bin/bash

پرسش و پاسخ شماره ۲۲

پرسش و پاسخ شماره ۲۲

چگونه می‌توانم به جای فقط اعداد صحیح، اعداد با ممیز شناور را در محاسبه استفاده کنم؟

حسابگر داخلی BASH فقط از اعداد صحیح استفاده می‌کند:

$ echo $((10/3))
3

برای اکثر عملیات درگیر با اعداد دارای ممیزشناور، باید از یک برنامه خارجی استفاده شود، به عنوان نمونه از bc، AWK یا dc:

$ echo "scale=3; 10/3" | bc
3.333

فرمان ‎ "scale=3"‎ به برنامه bc اعلام می‌کند که سه رقم دقت بعد از نقطه اعشاری لازم است.

همان مثال با dc( ماشین حساب شسته رفته و سبُک‌تر از bc):

$ echo "3 k 10 3 / p" | dc
3.333

k دقت اعشار را به 3 رقم تنظیم می‌کند، و p بالاترین قسمت پُشته را با یک کاراکتر سطر جدید چاپ می‌کند. به هر حال، پُشته جایگزین نمی‌شود.

اگر می‌خواهید اعداد اعشاری را مقایسه کنید(کوچکتر از، یا بزرگتر از) ، و bc گنو را دارید، می‌توانید چنین کنید:

# Bash
if (( $(bc <<< "1.4 < 2.5") )); then
  echo "1.4 is less than 2.5."
fi

اما،‎ x < y‎ توسط تمام نگارشهای bc پشتیبانی نمی‌شود:

# خیر HP-UX 10.20 این با برخی نگارشها کار می‌کند اما با
imadev:~$ bc <<< '1 < 2'
syntax error on line 1,

اگر می‌خواهید قابل حمل باشید، به مورد ماهرانه‌تری نیاز دارید:

# POSIX
case $(echo "1.4 - 2.5" | bc) in
  -*) echo "1.4 is less than 2.5";;
esac

این مثال 2.5 را از 1.4 تفریق می‌کند، و علامت نتیجه را کنترل می‌کند.اگر منفی باشد، عدد اول کوچکتر از دومی است. در حقیقت، ما با خروجی bc به عنوان عدد رفتار نمی‌کنیم، با آن به صورت یک رشته رفتار می‌کنیم، و فقط به اولین کاراکتر آن نگاه می‌کنیم.

میراث نگارش (Bourne):

# Bourne
case "`echo "1.4 - 2.5" | bc`" in
  -*) echo "1.4 is less than 2.5";;
esac

AWK نیز می‌تواند برای محاسبات به کار برود:

$ awk 'BEGIN {printf "%.3f\n", 10 / 3}'
3.333

در اینجا تفاوت ظریف اما مهمی بین راه حل bc و awk وجود دارد: bc فرمانها و عبارات را از ورودی استاندارد می‌خواند. از طرف دیگر awk عبارت را به عنوان بخشی از برنامه برآورد می‌کند. عبارتها در ورودی استاندارد سنجیده نمی‌شوند، یعنی فرمان ‎echo 10/3 | awk '{print $0}'‎ به جای ارزیابی، نتیجه عبارت ‎ 10/3‎ را چاپ می‌کند.

نگارشهای جدیدتر پوسته zsh و پوسته Korn یک حساب ممیز شناور داخلی، همراه با توابعی مانند‎ sin()‎ یا‎ cos()‎ در خود دارند. بنابراین بسیاری از این محاسبات، در ksh می‌توانند به طور بومی انجام شوند:

# ksh93
$ echo $((3.00000000000/7))
0.428571428571428571

مقایسه برابری دو عدد با ممیز شناور ، در واقع کار نابخردانه‌ای می‌باشد، دو محاسبه‌ای که روی کاغذ نتیجه یکسانی ارائه خواهند داد ممکن است در نتایج عددی ممیز شناور تفاوت بسیار جزئی ناشی از گِرد کردن و کوتاه‌سازی نشان بدهد. اگر می‌خواهید تعیین کنید که آیا دو عدد با ممیز شناور یکسان هستند، می‌توانید:

  • یا هر دو عدد را با دقت یکسان گِرد کنید، و بعد نتایج گِرد شده را برای برابری مقایسه کنید، یا
  • یک عدد را از دیگری تفریق نموده و مقدار خالص تفاضل را با مقدار ناچیزی به انتخاب خود مقایسه نمایید.

یکی از موارد بسیار اندکی که Bash به طور واقعی می‌تواند با اعداد ممیز شناور انجام بدهد، گرد نمودن آنها با استفاده از printf است:

# Bash 3.1
# به یکدیگر نزدیک باشند b و a ببینید اگر
# گرد کردن آنها تا دو رقم اعشار و مقایسه نتایج به عنوان رشته‌ را
a=3.002 b=2.998
printf -v a1 %.2f $a
printf -v b1 %.2f $b
if [[ $a1 = "$b1" ]]; then echo "a and b are the same, roughly"; fi

پیش‌بینی احتیاطی: بسیاری از مشکلاتی که به محاسبات ممیز شناور شباهت دارند در حقیقت می‌توانند فقط با اعداد صحیح حل بشوند، و بنابراین به این ابزارها نیازی نمی‌باشد-- به عنوان مثال، مشکلات مربوط به اعداد کسری. برای نمونه، جهت کنترل اینکه آیا نسبت دو عدد x و y، برابر با نسبت ‎   4:3 ‎ یا ‎ 16:9‎ می‌باشد، می‌توانید از موردی مشابه این سطرها استفاده کنید:

# Bash
# Variables x and y are integers
if (( $x*9-$y*16==0 )) ; then
   echo "16:9."
elif (( $x*3-$y*4==0 )) ; then
   echo "4:3."
else
   echo "Neither 16:9 nor 4:3."
fi

در یک بررسی استادانه‌تر، بدون استفاده از محاسبات ممیز شناور، می‌توانست تشخیص داده شود نزدیکترین نسبت 4:3 است یا 16:9. توجه نمایید که این مثال بسیار ساده‌ای می‌باشد و ظاهراً اعداد ممیز شناور و تقسیم را در گیر می‌سازد، که با اعداد صحیح و بدون تقسیم حل می‌شود. اگر امکان داشته باشد، به طور معمول تبدیل مشکل شما به محاسبات صحیح، ثمربخش‌تر از به کار بردن محاسبات ممیز شناور است.


CategoryShell

پرسش و پاسخ 22 (آخرین ویرایش ‎ed 2012-11-26 10:07:41 ‎ توسط geirha)