![쉘 스크립트에 매우 큰 숫자 추가](https://linux55.com/image/104084/%EC%89%98%20%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%97%90%20%EB%A7%A4%EC%9A%B0%20%ED%81%B0%20%EC%88%AB%EC%9E%90%20%EC%B6%94%EA%B0%80.png)
두 개의 숫자가 두 개의 서로 다른 파일에 저장되어 있다고 가정 a.txt
하고 b.txt
.
각 숫자는 충분히 크므로(30비트 이상) 사용된 숫자 데이터 유형은 지원되지 않습니다 bash
.
쉘에 어떻게 추가합니까?
답변1
십진수라고 가정하면 다음과 같이 할 수 있습니다.
paste -d + a.txt b.txt | bc
매우 긴 숫자 는 bc
래핑됩니다(구현에 따라 68자리 또는 69자리 이상). GNU를 사용하면 bc
환경 변수를 0으로 설정하여 비활성화할 수 있습니다 BC_LINE_LENGTH
. 예를 들면 다음과 같습니다.
paste -d + a.txt b.txt | BC_LINE_LENGTH=0 bc
답변2
비결은bash
덧셈을 수행하는 데 사용되지 않음1 .
먼저, 각 숫자를 별도의 변수로 읽어옵니다. 이는 파일에 다음이 포함되어 있다고 가정합니다.단 하나의 숫자그리고 다른 정보는 없습니다.
read a <a.txt
read b <b.txt
그런 다음 bc
계산기를 사용하여 결과를 얻으십시오.
bc <<<"$a + $b"
bc
"임의의 정밀 산술 언어 및 계산기"입니다.
결과를 변수에 저장하려면 다음을 수행하십시오 c
.
c="$( bc <<<"$a + $b" )"
구문이 이상하다고 느껴지면("here-string"이라고 하며 <<<
POSIX 셸 구문 및 일부 다른 셸에서 지원되는 확장임) 대신 Send add to를 사용할 수 있습니다.bash
printf
bc
printf '%s + %s\n' "$a" "$b" | bc
c
결과를 다음 위치에 다시 저장합니다 .
c="$( printf '%s + %s\n' "$a" "$b" | bc )"
1 두 개의 매우 큰 숫자를 더 하려면 다음을 수행하는 스크립트에 루틴을 구현 해야 합니다.bash
bash
임의의 정밀 연산. 이것은완전히 가능하지만 번거롭다bc
그리고 모든 Unix에는 이미 상대적으로 간단하고 접근 가능한 방식으로 이를 제공하는 이 기능이 포함되어 있기 때문에 필요하지 않습니다 .
답변3
지금은스티븐그리고쿠사로난다 라고, "정말로 그냥 bc를 사용하세요"라고 말하지만, 정말로 사용하고 싶다면세게 때리다또한 시작점은 다음과 같습니다(양의 정수만 해당). 소수와 음수를 구현하는 독자를 위한 연습용으로 남겨두겠습니다.
function arbadd {
addend1=$1
addend2=$2
sum=
bcsum=$(echo $addend1 + $addend2 | BC_LINE_LENGTH=0 bc)
# zero-pad the smallest number
while [ ${#addend1} -lt ${#addend2} ]
do
addend1=0${addend1}
done
while [ ${#addend2} -lt ${#addend1} ]
do
addend2=0${addend2}
done
carry=0
for((index=${#addend1}-1;index >= 0; index--))
do
case ${carry}${addend1:index:1}${addend2:index:1} in
(000) carry=0; sum=0${sum};;
(001|010|100) carry=0; sum=1${sum};;
(002|011|020|101|110) carry=0; sum=2${sum};;
(003|012|021|030|102|111|120) carry=0; sum=3${sum};;
(004|013|022|031|040|103|112|121|130) carry=0; sum=4${sum};;
(005|014|023|032|041|050|104|113|122|131|140) carry=0; sum=5${sum};;
(006|015|024|033|042|051|060|105|114|123|132|141|150) carry=0; sum=6${sum};;
(007|016|025|034|043|052|061|070|106|115|124|133|142|151|160) carry=0; sum=7${sum};;
(008|017|026|035|044|053|062|071|080|107|116|125|134|143|152|161|170) carry=0; sum=8${sum};;
(009|018|027|036|045|054|063|072|081|090|108|117|126|135|144|153|162|171|180) carry=0; sum=9${sum};;
(019|028|037|046|055|064|073|082|091|109|118|127|136|145|154|163|172|181|190) carry=1; sum=0${sum};;
(029|038|047|056|065|074|083|092|119|128|137|146|155|164|173|182|191) carry=1; sum=1${sum};;
(039|048|057|066|075|084|093|129|138|147|156|165|174|183|192) carry=1; sum=2${sum};;
(049|058|067|076|085|094|139|148|157|166|175|184|193) carry=1; sum=3${sum};;
(059|068|077|086|095|149|158|167|176|185|194) carry=1; sum=4${sum};;
(069|078|087|096|159|168|177|186|195) carry=1; sum=5${sum};;
(079|088|097|169|178|187|196) carry=1; sum=6${sum};;
(089|098|179|188|197) carry=1; sum=7${sum};;
(099|189|198) carry=1; sum=8${sum};;
(199) carry=1; sum=9${sum};;
esac
done
if [ $carry -eq 1 ]
then
sum=1${sum}
fi
printf "Sum = %s\n" "$sum"
}
나는 bc
거기에 비교를 남겼지만 비교를 위해 주석을 달았습니다.