การคูณทุบตีและการเพิ่ม


18
for k in {0..49};
do
a=$(($((2*$k))+1));
echo $a;
done

สวัสดีฉันต้องการนิพจน์ที่ง่ายขึ้นสำหรับบรรทัดที่สามหรืออาจใช้อันที่ไม่ใช้การทดแทนคำสั่ง


@Theophrastus: ตามที่แนะนำมันใช้งานได้ดี แต่ถ้าฉันต้องการใช้ expr แทน (())
AVS

นี่คือbashและไม่ใช่Cดังนั้นลบทั้งหมด;- ยกเว้นว่าคุณเขียนเป็นบรรทัดเอกพจน์
ott--

ดูเพิ่มเติมที่: unix.stackexchange.com/q/40786/117549
Jeff Schaller

declare -i a; for k in {0..49}; do a=2*$k+1; echo $a; done
Cyrus

1
Aside: $(( ... ))เป็นการขยายเลขคณิตไม่ใช่การทดแทนคำสั่ง
dave_thompson_085

คำตอบ:


28

ใช้การขยายเลขคณิต:

for (( k = 0; k < 50; ++k )); do
  a=$(( 2*k + 1 ))
  echo "$a"
done

การใช้exprยูทิลิตี้โบราณ

for (( k = 0; k < 50; ++k )); do
  a=$( expr 2 '*' "$k" + 1 )
  echo "$a"
done

การใช้bc -l( -lไม่จำเป็นจริง ๆ ในกรณีนี้เนื่องจากไม่มีการใช้ฟังก์ชันคณิตศาสตร์):

for (( k = 0; k < 50; ++k )); do
  a=$( bc -l <<<"2*$k + 1" )
  echo "$a"
done

การใช้bc -lเป็นกระบวนการร่วม (ทำหน้าที่เหมือนบริการการคำนวณในพื้นหลัง¹):

coproc bc -l

for (( k = 0; k < 50; ++k )); do
  printf "2*%d + 1\n" "$k" >&${COPROC[1]}
  read -u "${COPROC[0]}" a
  echo "$a"
done

kill "$COPROC_PID"

ภาพสุดท้ายนั้นดูสะอาดตาขึ้นในksh93:

bc -l |&
bc_pid="$!"

for (( k = 0; k < 50; ++k )); do
  print -p "2*$k + 1"
  read -p a
  print "$a"
done

kill "$bc_pid"

¹วิธีนี้แก้ไขปัญหาสำหรับฉันเมื่อฉันต้องการประมวลผลอินพุตจำนวนมากในลูป การประมวลผลจำเป็นต้องมีการคำนวณจุดลอยตัวบางส่วน แต่การวางไข่bcสองสามครั้งในลูปพิสูจน์แล้วว่าช้ามาก ใช่ฉันสามารถแก้ไขมันได้หลายวิธี แต่ฉันก็เบื่อ ...



5

คุณสามารถใช้letคำสั่งเพื่อบังคับการคำนวณ

let a="2*k+1"

โปรดทราบว่าเราไม่ต้องการ$kในโครงสร้างนี้ ง่ายkจะทำงาน


4
ที่ล้มเหลวหากมีไฟล์ที่เรียกว่าa=2whateverk+1ในไดเรกทอรีปัจจุบัน ที่แย่กว่านั้นถ้ามีไฟล์ที่เรียกa=2+b[$(reboot)]k+1ว่าเรียกrebootคำสั่ง ดีที่สุดคือการใช้((...))ที่นี่ ( ((a = 2 * k + 1))) หรือไวยากรณ์ POSIX:a=$((2 * k + 1))
Stéphane Chazelas

เราสามารถพูดได้ let a="2*k+1"เพื่อแก้ปัญหานั้น
Stephen Harris

2

การขยายเลขคณิตที่คุณอาจต้องการคือ:

a=$(( 1+2*k ))

ที่จริงแล้วคุณไม่จำเป็นต้องใช้ตัวแปร:

for k in {0..49}; do
    echo "$(( 1 + 2*k ))"
done

หรือตัวแปรการนับสามารถย้ายไปยังfor ((…))ลูป:

for (( k=0;k<50;k++ )); do
    a=$(( 1+2*k ))
    printf '%s\n' "$a"
done

สำหรับ ((…)) ลูป

และในกรณีนั้นการขยายเลขคณิตสามารถถูกย้ายไปไว้ในวง for:

for (( k=0 ; a=1+2*k , k<50 ;  k++)); do
    printf '%s\n' "$a"
done

หรือเพื่อรับค่าทั้งหมดในอาร์เรย์:

for (( k=0 ; a[k]=1+2*k , k<49 ;  k++ )); do :; done
printf '%s\n' "${a[@]}"

ไม่มีสูตร

แต่อาจเป็นวิธีที่สั้นที่สุดในการหลีกเลี่ยงการขยายเลขคณิตใด ๆ คือการเพิ่มตัวแปรสองครั้ง:

for (( k=0,a=1 ; k<50 ;  k++,a++,a++ )); do
    printf '%s\n' "$a"
done

หรือง่ายยิ่งขึ้นเพียงใช้ seq:

seq 1 2 100
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.