มีขีด จำกัด สำหรับความสามารถในการประเมินผลทางคณิตศาสตร์ของbash
เชลล์ คู่มือฉบับย่อเกี่ยวกับแง่มุมของเชลล์ทางคณิตศาสตร์นี้ แต่ระบุว่า :
การประเมินจะทำในจำนวนเต็มที่มีความกว้างคงที่โดยไม่มีการตรวจสอบการล้น แต่การหารด้วย 0 จะถูกดักและตั้งค่าสถานะเป็นข้อผิดพลาด โอเปอเรเตอร์และลำดับความสำคัญการเชื่อมโยงและค่าต่าง ๆ นั้นเหมือนกับในภาษา C
จำนวนเต็มที่มีความกว้างคงที่ซึ่งหมายถึงนี้เป็นจริงเกี่ยวกับชนิดข้อมูลที่ใช้ (และเฉพาะของสาเหตุนี้เกินกว่านี้) แต่ค่าขีด จำกัด จะแสดง/usr/include/limits.h
ในแบบนี้:
# if __WORDSIZE == 64
# define ULONG_MAX 18446744073709551615UL
# ifdef __USE_ISOC99
# define LLONG_MAX 9223372036854775807LL
# define ULLONG_MAX 18446744073709551615ULL
และเมื่อคุณรู้ว่าคุณสามารถยืนยันสถานะของความจริงเช่นนี้:
# getconf -a | grep 'long'
LONG_BIT 64
ULONG_MAX 18446744073709551615
นี่เป็นจำนวนเต็ม 64 บิตและนี่แปลโดยตรงในเชลล์ในบริบทของการประเมินทางคณิตศาสตร์:
# echo $(((2**63)-1)); echo $((2**63)); echo $(((2**63)+1)); echo $((2**64))
9223372036854775807 //the practical usable limit for your everyday use
-9223372036854775808 //you're that much "away" from 2^64
-9223372036854775807
0
# echo $((9223372036854775808+9223372036854775807))
-1
ดังนั้นระหว่าง 2 63 2 64 -1 คุณจะได้รับจำนวนเต็มเชิงลบแสดงวิธีห่างไกลจาก ULONG_MAX คุณเป็น1 เมื่อการประเมินถึงขีด จำกัด นั้นและมากเกินไปคุณจะไม่ได้รับคำเตือนใด ๆ และลำดับของการประเมินนั้นจะถูกรีเซ็ตเป็น 0 ซึ่งอาจทำให้เกิดพฤติกรรมที่ผิดปกติบางอย่างเช่นการยกกำลังเชื่อมโยงทางขวาเช่น:
echo $((6**6**6)) 0 // 6^46656 overflows to 0
echo $((6**6**6**6)) 1 // 6^(6^46656) = 6^0 = 1
echo $((6**6**6**6**6)) 6 // 6^(6(6^46656)) = 6^(6^0) = 6^1
echo $((6**6**6**6**6**6)) 46656 // 6^(6^(6^(6^46656))) = 6^6
echo $((6**6**6**6**6**6**6)) 0 // = 6^6^6^1 = 0
...
การใช้sh -c 'command'
ไม่ได้เปลี่ยนแปลงอะไรดังนั้นฉันต้องสมมติว่านี่เป็นเรื่องปกติและเป็นไปตามมาตรฐาน ตอนนี้ฉันคิดว่าฉันมีความเข้าใจพื้นฐาน แต่เป็นรูปธรรมเกี่ยวกับช่วงและขีด จำกัด ทางคณิตศาสตร์และความหมายในเชลล์สำหรับการประเมินการแสดงออกฉันคิดว่าฉันสามารถมองอย่างรวดเร็วว่าข้อมูลประเภทใดที่ซอฟต์แวร์อื่นใช้ใน Linux ฉันใช้bash
แหล่งข้อมูลบางอย่างเพื่อเพิ่มอินพุตของคำสั่งนี้:
{ shopt -s globstar; for i in /path/to/source_bash-4.2/include/**/*.h /usr/include/**/*.h; do grep -HE '\b(([UL])|(UL)|())LONG|\bFLOAT|\bDOUBLE|\bINT' $i; done; } | grep -iE 'bash.*max'
bash-4.2/include/typemax.h:# define LLONG_MAX TYPE_MAXIMUM(long long int)
bash-4.2/include/typemax.h:# define ULLONG_MAX TYPE_MAXIMUM(unsigned long long int)
bash-4.2/include/typemax.h:# define INT_MAX TYPE_MAXIMUM(int)
มีการส่งออกมากขึ้นกับif
งบและฉันสามารถค้นหาคำสั่งเช่นawk
ฯลฯ ฉันแจ้งให้ทราบล่วงหน้าเกินไปการแสดงออกปกติผมใช้ไม่ได้จับอะไรเกี่ยวกับเครื่องมือความแม่นยำโดยพลฉันมีเช่นและbc
dc
คำถาม
- อะไรคือเหตุผลที่ไม่เตือนคุณ (เช่นเดียวกับ
awk
เมื่อประเมิน 2 ^ 1024) เมื่อการประเมินทางคณิตศาสตร์ของคุณล้น ทำไมจำนวนเต็มลบระหว่าง 2 63และ 2 64 -1 ถึงผู้ใช้ปลายทางเมื่อเขาประเมินบางอย่าง - ฉันได้อ่านที่ไหนซักแห่งที่ยูนิกซ์บางรสชาติสามารถเปลี่ยน ULONG_MAX แบบโต้ตอบได้? มีใครเคยได้ยินเรื่องนี้บ้างไหม?
- หากมีคนเปลี่ยนค่าจำนวนเต็มสูงสุดโดยไม่ได้ลงนาม
limits.h
แล้วคอมไพล์อีกbash
ครั้งสิ่งที่เราคาดหวังจะเกิดขึ้น?
บันทึก
1. ฉันต้องการแสดงให้เห็นชัดเจนยิ่งขึ้นในสิ่งที่ฉันเห็นเนื่องจากเป็นสิ่งเชิงประจักษ์ที่ง่ายมาก สิ่งที่ฉันสังเกตเห็นคือ:
- (a) การประเมินใด ๆ ที่ให้ <2 ^ 63-1 ถูกต้อง
- (b) การประเมินใด ๆ ที่ให้ => 2 ^ 63 สูงสุด 2 ^ 64 ให้จำนวนเต็มลบ:
- ช่วงของจำนวนเต็มนั้นคือ x ถึง y x = -9223372036854775808 และ y = 0
เมื่อพิจารณาถึงสิ่งนี้การประเมินที่เป็นเช่น (b) สามารถแสดงเป็น 2 ^ 63-1 บวกบางอย่างภายใน x..y ตัวอย่างเช่นหากเราถูกขอให้ประเมิน (2 ^ 63-1) +100 002 (แต่อาจเป็นจำนวนที่น้อยกว่าใน (a)) เราจะได้รับ -9223372036854675807 ฉันแค่บอกชัดเจนว่าฉันเดา แต่นี่ก็หมายความว่าทั้งสองแสดงออกต่อไปนี้:
- (2 ^ 63-1) + 100 002 และ;
- (2 ^ 63-1) + (LLONG_MAX - {สิ่งที่เชลล์มอบให้เรา ((2 ^ 63-1) + 100 002) ซึ่งคือ -9223372036854675807} ดีโดยใช้ค่าบวกที่เรามี
- (2 ^ 63-1) + (9223372036854775807 - 922337203685464680807 = 100 000)
- = 9223372036854775807 + 100 000
สนิทกันมาก นิพจน์ที่สองคือ "2" นอกเหนือจาก (2 ^ 63-1) + 100 002 นั่นคือสิ่งที่เรากำลังประเมิน นี่คือสิ่งที่ฉันหมายถึงเมื่อคุณได้รับจำนวนเต็มลบแสดงว่าคุณอยู่ห่างจาก 2 ^ 64 มากแค่ไหน ฉันหมายความว่าด้วยจำนวนเต็มลบและความรู้เกี่ยวกับขีด จำกัด คุณไม่สามารถประเมินได้ภายในช่วง x ..y ใน bash shell แต่คุณสามารถไปที่อื่น - ข้อมูลสามารถใช้งานได้ถึง 2 ^ 64 ในแง่นั้น (ฉันสามารถเพิ่ม ขึ้นบนกระดาษหรือใช้เป็น bc) นอกเหนือจากนั้นพฤติกรรมจะคล้ายกับ 6 ^ 6 ^ 6 ถึงขีด จำกัด ดังที่อธิบายไว้ด้านล่างใน Q ...
bc
$num=$(echo 6^6^6 | bc)
แต่น่าเสียดายที่bc
วางในบรรทัดแบ่งดังนั้นคุณต้องnum=$(echo $num | sed 's/\\\s//g')
หลังจากนั้น ถ้าคุณทำมันในไพพ์มีอักขระขึ้นบรรทัดใหม่จริงซึ่งอึดอัดใจกับ sed แม้ว่าจะnum=$(echo 6^6^3 | bc | perl -pne 's/\\\s//g')
ใช้ได้ num2=$(echo "$num * 2" | bc)
ในทั้งสองกรณีขณะนี้คุณมีจำนวนเต็มซึ่งสามารถนำมาใช้เช่นการ
bc
BC_LINE_LENGTH=0