Giả sử rằng hai số được lưu trữ trong hai tệp khác nhau a.txt
và b.txt
.
Mỗi số đủ lớn (hơn 30 chữ số) để không được hỗ trợ bởi loại dữ liệu số được sử dụng bởi bash
.
Làm thế nào tôi có thể thêm chúng trong vỏ?
python
như phk đề xuất
Giả sử rằng hai số được lưu trữ trong hai tệp khác nhau a.txt
và b.txt
.
Mỗi số đủ lớn (hơn 30 chữ số) để không được hỗ trợ bởi loại dữ liệu số được sử dụng bởi bash
.
Làm thế nào tôi có thể thêm chúng trong vỏ?
python
như phk đề xuất
Câu trả lời:
Giả sử chúng là số thập phân, bạn có thể làm:
paste -d + a.txt b.txt | bc
Coi chừng bc
dòng đó kết thúc các số rất dài (hơn 68 hoặc 69 chữ số tùy theo việc thực hiện). Với GNU bc
, bạn có thể vô hiệu hóa nó bằng cách đặt BC_LINE_LENGTH
biến môi trường thành 0, như với:
paste -d + a.txt b.txt | BC_LINE_LENGTH=0 bc
Bí quyết là không sử dụng bash
để thực hiện phép cộng 1 .
Đầu tiên, đọc mỗi số thành một biến riêng biệt. Điều này giả định rằng các tệp chỉ chứa một số và không có thông tin khác.
a="$(<a.txt)"
b="$(<b.txt)"
Sau đó sử dụng bc
máy tính để nhận kết quả:
bc <<<"$a + $b"
bc
là một "ngôn ngữ và máy tính số học chính xác tùy ý".
Để lưu trữ kết quả trong một biến c
:
c="$( bc <<<"$a + $b" )"
Nếu <<<
cú pháp cảm thấy kỳ lạ (nó được gọi là "chuỗi ở đây" và là một phần mở rộng cho cú pháp shell POSIX được hỗ trợ bởi bash
và một vài shell khác), thay vào đó bạn có thể sử dụng printf
để gửi bổ sung tới bc
:
printf '%s + %s\n' "$a" "$b" | bc
Và lưu trữ kết quả trong c
một lần nữa:
c="$( printf '%s + %s\n' "$a" "$b" | bc )"
1 Sử dụng bash
để thực hiện việc cộng hai số cực lớn sẽ đòi hỏi phải thực hiện, trong bash
kịch bản, một thói quen để thực hiện số học chính xác tùy ý . Điều này là hoàn toàn có thể thực hiện được, nhưng cồng kềnh và không cần thiết vì mọi Unix đi kèm bc
đã cung cấp dịch vụ này cho bạn theo cách tương đối dễ dàng và dễ tiếp cận.
read a < a.txt
. Điều đó cũng sẽ quan tâm đến việc tước bỏ khoảng trống hàng đầu và dấu vết nếu có (giả sử $IFS
chưa được sửa đổi).
echo "\"hello\""
, thứ bên trong $(...)
không phải là một chuỗi được truyền dưới dạng đối số cho một chương trình khác và shell biết cách xử lý các dấu ngoặc kép. Đây cũng là lý do tại sao sử dụng $(...)
chứ không phải backticks là tốt hơn; bạn có thể viết $( ... $( ... ) )
mà không có bất kỳ sự mơ hồ nào, trong khi điều tương tự sử dụng backticks là ... khó xử.
bc
.
Như cả Stéphane và Kusalananda đều nói , "thực sự, chỉ sử dụng bc", nhưng nếu bạn thực sự muốn sử dụng bash để thêm vào, thì đây là điểm khởi đầu (chỉ số nguyên dương) - Tôi sẽ để nó như một bài tập để người đọc thực hiện số thập phân và số âm:
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"
}
Tôi đã để lại sự bc
so sánh trong đó, nhưng nhận xét, để so sánh.
python
hoặc tương tự trong trường hợp đó.