정수를 소수로 인수분해합니다.
bash$ factor 27417 27417: 3 13 19 37 |
무한 정밀도(arbitrary precision)의 계산을 가능케 해 주는 유연한 유틸리티.
bc는 약간 애매한 C 문법을 따릅니다.
dc는 RPN("역폴란드식 표기법, Reverse Polish Notation")을 씁니다.
둘 중에서 스크립트에서 쓰기에는 bc가 더 유용해 보입니다. bc는 꽤 잘 동작하는 유닉스 유틸리티이기 때문에 파이프에서 쓰일 수도 있습니다.
bash는 부동소수점 연산을 할 수 없고 몇몇 중요한 산술적인 기능이 빠져 있지만 다행히, bc가 이런 부분을 메꿔줍니다.
다음은 bc로 스크립트 변수를 계산하기 위한 간단한 틀입니다. 여기서는 명령어 치환을 사용합니다.
variable=$(echo "OPTIONS; OPERATIONS" | bc) |
예 12-28. 저당에 대한 월 상환액(Monthly Payment on a Mortgage)
#!/bin/bash # monthlypmt.sh: 저당에 대한 월 상환액을 계산. # 이 스크립트는 Jeff Schmidt 와 Mendel Cooper(이 문서의 저자인 본인)이 작성한 # "mcalc"(저당액 계산기, mortgage calculator) 패키지의 수정본입니다. # http://www.ibiblio.org/pub/Linux/apps/financial/mcalc-1.6.tar.gz [15k] echo echo "원금, 이자율, 저당 기간을 입력하면 월 상환액을 계산합니다." bottom=1.0 echo echo -n "원금을 넣으세요(콤마 없이) " read principal echo -n "이자율을 넣으세요(퍼센트로) " # 만약에 12% 라면 ".12"가 아니고 "12"라고 입력. read interest_r echo -n "기간을 넣으세요(월 단위) " read term interest_r=$(echo "scale=9; $interest_r/100.0" | bc) # 소수로 변환. # "scale" 로 소수점 이하 몇 자리까지 표현할 것인지를 결정. interest_rate=$(echo "scale=9; $interest_r/12 + 1.0" | bc) top=$(echo "scale=9; $principal*$interest_rate^$term" | bc) echo; echo "시간이 좀 걸리므로, 느긋하게 기다리기 바랍니다." let "months = $term - 1" for ((x=$months; x > 0; x--)) do bot=$(echo "scale=9; $interest_rate^$x" | bc) bottom=$(echo "scale=9; $bottom+$bot" | bc) # bottom = $(($bottom + $bot")) done # let "payment = $top/$bottom" payment=$(echo "scale=2; $top/$bottom" | bc) # 달러와 센트 표시를 위해 소수점 이하 두 자리만 표시. echo echo "월 상환액 = \$$payment" # 결과 앞에 달러 표시를 에코. echo exit 0 # 연습문제: # 1) 원금 입력시 콤마를 쓸 수 있게 해 보세요. # 2) 이자 입력시 퍼센트 표시나 소수점 표시 둘 다 쓸 수 있게 해 보세요. # 3) 더 멋있는 스크립트로 만들려면, # 완전한 부채 상환표(amortization tables)를 출력하도록 고쳐 보세요. |
예 12-29. 진법 변환(Base Conversion)
: ########################################################################## # Shellscript: base.sh - 숫자를 다른 진법으로 보여줌(Bourne Shell) # Author : Heiner Steven (heiner.steven@odn.de) # Date : 07-03-95 # Category : Desktop # $Id: base.sh,v 1.2 2000/02/06 19:55:35 heiner Exp $ ########################################################################## # Description # # Changes # 21-03-95 stv 입력이 0xb 일 경우 생기는 에러 고침(0.2) ########################################################################## # ==> 스크립트 저자의 허락하에 사용함. # ==> 이 표시는 이 문서의 저자가 주석을 붙인 것임. NOARGS=65 PN=`basename "$0"` # 프로그램 이름 VER=`echo '$Revision: 1.2 $' | cut -d' ' -f2` # ==> VER=1.2 Usage () { echo "$PN - 숫자를 다른 진법으로 보여줌, $VER (stv '95) 사용법: $PN [숫자 ...] 숫자를 알려주지 않으면 표준 입력에서 읽습니다. 가능한 숫자로는 2 진수 0b 로 시작(즉, 0b1100) 8 진수 0 으로 시작(즉, 014) 16 진수 0x 로 시작(즉, 0xc) 10 진수 그 외(즉, 12)" >&2 exit $NOARGS } # ==> 사용법을 알려 주는 함수. Msg () { for i # ==> in [list] 가 빠져 있습니다. do echo "$PN: $i" >&2 done } Fatal () { Msg "$@"; exit 66; } PrintBases () { # 숫자의 진법을 결정. for i # ==> in [list] 가 빠져 있어서... do # ==> 명령어줄 인자(들)에 대해서 동작. case "$i" in 0b*) ibase=2;; # 2진수 0x*|[a-f]*|[A-F]*) ibase=16;; # 16진수 0*) ibase=8;; # 8진수 [1-9]*) ibase=10;; # 10진수 *) Msg "부적절한 숫자($i)라 무시합니다." continue;; esac # 접두사를 제거하고, 16진수를 대문자로 변환(bc에서 필요함). number=`echo "$i" | sed -e 's:^0[bBxX]::' | tr '[a-f]' '[A-F]'` # ==> sed 구분자로 "/"가 아닌 ":"를 썼네요. # 일단 10진수로 변환 dec=`echo "ibase=$ibase; $number" | bc` # ==> 'bc' 는 계산용 유틸리티죠. case "$dec" in [0-9]*) ;; # 됐군요. *) continue;; # 에러네요. 무시합니다. esac # 변환된 숫자들을 한 줄로 출력합니다. # ==> 'here document' 는 명령어 목록을 'bc'로 입력시켜 줍니다. echo `bc <<! obase=16; "hex="; $dec obase=10; "dec="; $dec obase=8; "oct="; $dec obase=2; "bin="; $dec ! ` | sed -e 's: : :g' done } while [ $# -gt 0 ] do case "$1" in --) shift; break;; -h) Usage;; # ==> 도움말. -*) Usage;; *) break;; # 첫번째 숫자. esac # ==> 입력에 대해서 에러 체크를 더 하면 좀 더 유용하게 쓸 수 있을 겁니다. shift done if [ $# -gt 0 ] then PrintBases "$@" else # 표준입력에서 읽기. while read line do PrintBases $line done fi |
bc를 실행시키는 다른 방법으로는 명령어 치환 블럭 안에서 here document를 쓰는 것입니다. 이 방법은 스크립트에서 bc로 옵션과 명령어를 넘기려고 할 때 특히 적당합니다.
variable=`bc << LIMIT_STRING options statements operations LIMIT_STRING ` ...아니면... variable=$(bc << LIMIT_STRING options statements operations LIMIT_STRING ) |
예 12-30. 다른 방법으로 bc 실행
#!/bin/bash # 'bc'를 'here document'와 같이 쓴 것을 명령어 치환을 써서 실행. var1=`bc << EOF 18.33 * 19.78 EOF ` echo $var1 # 362.56 # $( ... ) 표기법도 역시 됩니다. v1=23.53 v2=17.881 v3=83.501 v4=171.63 var2=$(bc << EOF scale = 4 a = ( $v1 + $v2 ) b = ( $v3 * $v4 ) a * b + 15.35 EOF ) echo $var2 # 593487.8452 var3=$(bc -l << EOF scale = 9 s ( 1.7 ) EOF ) # 1.7 라디안의 사인값을 리턴. # "-l" 옵션은 'bc'의 수학 라이브러리를 호출합니다. echo $var3 # .991664810 # 이제, 함수에서 해 보죠... hyp= # 전역 변수 선언. hypotenuse () # 정삼각형의 빗변을 계산. { hyp=$(bc -l << EOF scale = 9 sqrt ( $1 * $1 + $2 * $2 ) EOF ) # 불행하게도, Bash 함수에서는 부동형 값을 리턴할 수 없습니다. } hypotenuse 3.68 7.31 echo "hypotenuse = $hyp" # 8.184039344 exit 0 |