Suppose that two numbers are stored in two different files, a.txt and b.txt.
Each number is large enough (more than 30 digits) to not be supported by the numeric data type used by bash.
How may I add them in the shell?
Suppose that two numbers are stored in two different files, a.txt and b.txt.
Each number is large enough (more than 30 digits) to not be supported by the numeric data type used by bash.
How may I add them in the shell?
Assuming they are decimal numbers, You could do:
paste -d + a.txt b.txt | bc
Beware that bc line-wraps very long numbers (more than 68 or 69 digits depending on the implementation). With GNU bc, you can disable it by setting the BC_LINE_LENGTH environment variable to 0, like with:
paste -d + a.txt b.txt | BC_LINE_LENGTH=0 bc
The trick is to not use bash to perform the addition1.
First, read each number into a separate variable. This assumes that the files contain only a number and no other information.
read a <a.txt
read b <b.txt
Then use the bc calculator to get the result:
bc <<<"$a + $b"
bc is an "arbitrary-precision arithmetic language and calculator".
To store the result in a variable c:
c="$( bc <<<"$a + $b" )"
If the <<< syntax feels weird (it's called a "here-string" and is an extension to the POSIX shell syntax supported by bash and a few other shells), you may instead use printf to send the addition to bc:
printf '%s + %s\n' "$a" "$b" | bc
And storing the result in c again:
c="$( printf '%s + %s\n' "$a" "$b" | bc )"
1 Using bash to perform the addition of two extremely large numbers would require the implementation, in the bash script, of a routine for doing arbitrary-precision arithmetic. This is perfectly doable, but cumbersome and unnecessary since every Unix comes with bc, which already provides this service to you in a relatively easy and accessible way.
As both Stéphane and Kusalananda said, "really, just use bc", but if you really want to use bash for addition, here's a starting point (positive integers only) -- I'll leave it as an exercise for the reader to implement decimals and negative numbers:
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"
}
I've left the bc comparison in there, but commented out, for comparison.