เข้าใจ“ ibase” และ“ obase” ในกรณีที่มีการแปลงกับ bc หรือไม่


22

ฉันมักจะใช้bcยูทิลิตี้สำหรับการแปลงฐานสิบหกเป็นทศนิยมและในทางกลับกัน แต่ก็เป็นบิตลองผิดลองถูกอยู่เสมอวิธีการibaseและobaseควรจะกำหนดค่า ตัวอย่างเช่นที่นี่ฉันต้องการแปลงค่าฐานสิบหก C0 เป็นทศนิยม:

$ echo "ibase=F;obase=A;C0" | bc
180
$ echo "ibase=F;obase=10;C0" | bc
C0
$ echo "ibase=16;obase=A;C0" | bc
192

ตรรกะที่นี่คืออะไร? obase( Aในตัวอย่างที่สามของฉัน) ต้องอยู่ในฐานเดียวกันกับค่าที่แปลง ( C0ในตัวอย่างของฉัน) และibase( 16ในตัวอย่างที่สาม) ต้องอยู่ในฐานที่ฉันแปลงไป?


1
สำหรับการคำนวณเลขฐานสิบหก (อินพุตและเอาต์พุตเป็นฐานสิบหก) ฉันต้องตั้งค่า obase ก่อน ibase!
Paschalis

คำตอบ:


36

สิ่งที่คุณต้องการพูดจริง ๆ คือ:

$ echo "ibase=16; C0" | bc
192

สำหรับฐานสิบหกถึงทศนิยมและ:

$ echo "obase=16; 192" | bc
C0

สำหรับทศนิยมฐานสิบหก

คุณไม่จำเป็นต้องให้ทั้งสองibaseและobaseสำหรับการแปลงใด ๆ ที่เกี่ยวข้องกับตัวเลขทศนิยมเนื่องจากการตั้งค่าเหล่านี้เริ่มต้นที่ 10

คุณไม่จำเป็นต้องให้ทั้งสำหรับการแปลงเช่นไบนารีเพื่อ hex ในกรณีนี้ฉันพบว่าง่ายที่สุดที่จะเข้าใจสิ่งต่าง ๆ ถ้าคุณให้obaseก่อน:

$ echo "obase=16; ibase=2; 11000000" | bc
C0

หากคุณให้ibaseก่อนจะเปลี่ยนการตีความของการobaseตั้งค่าต่อไปนี้เพื่อให้คำสั่งจะต้องเป็น:

$ echo "ibase=2; obase=10000; 11000000" | bc
C0

นี่เป็นเพราะตามลำดับนี้obaseค่าจะถูกแปลเป็นเลขฐานสองดังนั้นคุณต้องให้ 10,000 16 = 16 เพื่อรับเอาต์พุตในฐานสิบหก นั่นคือเงอะงะ


ตอนนี้เรามาดูสาเหตุที่ตัวอย่างสามข้อของคุณมีพฤติกรรมเหมือนที่ทำกัน

  1. echo "ibase=F;obase=A;C0" | bc

    180

    ที่กำหนดฐานการป้อนข้อมูลถึง 15 และฐานการส่งออกถึง 10 เนื่องจากค่าหลักเดียวคือการตีความใน hex, ตาม POSIX สิ่งนี้ขอbcบอกคุณว่าC0₁₅อยู่ในฐานA₁₅ = 10 และตอบได้อย่างถูกต้อง 180 though ถึงแม้ว่านี่ไม่ใช่คำถามที่คุณตั้งใจถามอย่างแน่นอน

  2. echo "ibase=F;obase=10;C0" | bc

    C0

    นี่คือการแปลงค่าว่างในฐาน 15

    ทำไม? ข้อแรกเพราะFตัวเลขหลักเดียวตีความเป็นเลขฐานสิบหกดังที่ฉันได้ชี้ให้เห็นในตัวอย่างก่อนหน้านี้ แต่ตอนนี้เมื่อคุณตั้งค่าเป็นฐาน 15 การตั้งค่าฐานผลลัพธ์ต่อไปนี้จะถูกตีความเช่นนั้นและ 10 and = 15 ดังนั้นคุณจึงมีการแปลงค่าว่างจากC0₁₅ถึงC0₁₅

    ถูกต้องเอาต์พุตไม่ได้เป็น hex ตามที่คุณสมมติมันอยู่ในฐาน 15!

    คุณสามารถพิสูจน์นี้เพื่อตัวเองโดยพยายามที่จะแปลงแทนF0 C0เนื่องจากไม่มีFตัวเลขในฐาน 15 ให้bcจับกับE0และให้E0เป็นเอาท์พุท

  3. echo "ibase=16; obase=A; C0"

    192

    นี่เป็นเพียงหนึ่งในสามตัวอย่างของคุณที่น่าจะใช้งานได้จริง

    มันกำลังเปลี่ยนฐานอินพุตเป็น hex ก่อนดังนั้นคุณไม่จำเป็นต้องขุดลงในข้อมูลจำเพาะ POSIX อีกต่อไปเพื่อทำความเข้าใจว่าทำไมAตีความเป็น hex, 10 ในกรณีนี้ ปัญหาเดียวของมันคือมันซ้ำซ้อนในการตั้งฐานเอาท์พุทเป็นA₁₆ = 10 เนื่องจากเป็นค่าเริ่มต้น


7

การตั้งค่าibaseหมายความว่าคุณต้องตั้งค่าobaseในฐานเดียวกันนั้น การอธิบายตัวอย่างของคุณจะแสดงสิ่งนี้:

echo "ibase=F;obase=A;C0" | bc

คุณตั้งค่าbcให้พิจารณาหมายเลขอินพุตตามที่แสดงในฐาน 15 ด้วย "ibase = F" "obase = A" ตั้งค่าหมายเลขเอาต์พุตเป็นฐาน 10 ซึ่งเป็นค่าเริ่มต้น

bc อ่าน C0 เป็นฐาน 15: C = 12 12 * 15 = 180


echo "ibase=F;obase=10;C0" | bc

ในที่นี้คุณตั้งค่าอินพุตเป็นฐาน 15 และเอาต์พุตเป็น 10 - ในฐาน 15 ดังนั้นฐานเอาต์พุตคือ 15 อินพุต C0 ในฐาน 15 คือเอาต์พุต C0 ในฐาน 15


echo "ibase=16;obase=A;C0" | bc

ตั้งค่าอินพุตเป็นฐาน 16 เอาต์พุตไปยังฐาน 10 (A ในฐาน 16 คือ 10 ในฐาน 10)

C0 แปลงเป็นฐาน 10 คือ: 12 * 16 = 192


กฎส่วนบุคคลของฉันคือการตั้งค่า obase ก่อนเพื่อที่ฉันจะสามารถใช้ฐาน 10 จากนั้นตั้งค่า ibase และใช้ฐาน 10

โปรดทราบว่าbcมีข้อยกเว้นแดกดัน: ibase=Aและobase=Aตั้งค่าอินพุตและเอาต์พุตเป็นฐาน 10 เสมอจากbcman page:

Single digit numbers always have the value of the digit 
regardless of the value of ibase.

ลักษณะการทำงานนี้เป็นที่ประดิษฐานในคุณสมบัติของbc: จาก2,004 OpenGroup bcสเปค :

When either ibase or obase is assigned a single digit value from 
the list in 'Lexical Conventions in bc', the value shall be assumed
in hexadecimal. (For example, ibase=A sets to base ten, regardless 
of the current ibase value.) Otherwise, the behavior is undefined 
when digits greater than or equal to the value of ibase appear in
the input.

นั่นเป็นสาเหตุที่การibase=Fตั้งค่าเปลี่ยนฐานอินพุตของคุณเป็นฐาน 15 และทำไมฉันแนะนำให้ตั้งฐานโดยใช้ฐาน 10 เสมอหลีกเลี่ยงความสับสน


@ StéphaneChazelas - ฉันมีความทรงจำเกี่ยวกับ "ibase = A" ที่ทำงานกับเครื่อง SysVr3 ในปี 1989 หรือมากกว่านั้น ฉันพนันได้เลยว่ามันกลับไปไกลกว่า Single Unix Spec ฉันไม่สามารถอ้างอิงได้เร็วขึ้น
Bruce Ediger

ฉันคิดว่านั่นเป็นเพราะมีการเชื่อมโยงมากขึ้นเกี่ยวกับรายละเอียดที่เก่ากว่าเพราะพวกเขาได้รับรอบนาน สิ่งเดียวกันนี้เกิดขึ้นสำหรับ apache / mysql / bugzilla ... เอกสารที่ google ให้เอกสารแก่คุณแก่รุ่นก่อนแทนที่จะเป็นรุ่นล่าสุด
Stéphane Chazelas

5

ตัวเลขทั้งหมดจะถูกตีความโดย GNU bc เป็นฐานอินพุตปัจจุบันที่มีผลบังคับใช้สำหรับคำสั่งที่ปรากฏในตัวเลขเมื่อคุณใช้ตัวเลขภายนอกอินพุตปัจจุบันตีความพวกเขาเป็นตัวเลขสูงสุดที่มีอยู่ในฐาน (9 เป็นทศนิยม) เมื่อส่วนหนึ่ง ของตัวเลขหลายหลักหรือเป็นค่าปกติเมื่อใช้เป็นตัวเลขหลักเดียว ( A== 10 เป็นทศนิยม)

จากGNU bc manual :

ตัวเลขหลักเดียวมักจะมีค่าของหลักโดยไม่คำนึงถึงความคุ้มค่าของibase (เช่น A = 10) สำหรับตัวเลขหลายหลักbcเปลี่ยนตัวเลขอินพุตทั้งหมดที่มากกว่าหรือเท่ากับibaseเป็นค่าibase -1 สิ่งนี้ทำให้หมายเลขนั้นเป็นตัวเลขFFF3 หลักที่ใหญ่ที่สุดของฐานอินพุตเสมอ

อย่างไรก็ตามคุณควรทราบว่ามาตรฐาน POSIX เพียงกำหนดพฤติกรรมนี้สำหรับการมอบหมายงานไปibaseและobaseและไม่ได้อยู่ในบริบทอื่น ๆ

จากข้อมูลจำเพาะ SUS บน bc :

เมื่อibaseหรือobaseถูกกำหนดค่าตัวเลขหลักเดียวจากรายการใน Lexical Conventions ใน bc ค่าจะถูกสมมติเป็นเลขฐานสิบหก (ตัวอย่างเช่นibase = A ตั้งค่าเป็นฐานสิบโดยไม่คำนึงถึงค่าibaseปัจจุบัน) มิฉะนั้นการทำงานจะไม่ได้กำหนดเมื่อตัวเลขที่มากกว่าหรือเท่ากับค่าของibaseปรากฏขึ้นในอินพุต ทั้งibaseและobaseจะมีค่าเริ่มต้นเท่ากับ 10

ปัจจัยสำคัญที่คุณขาดหายไปคือ F ไม่ได้อยู่ในความจริงสิบหก แต่จริงๆแล้วคือสิบห้าดังนั้นเมื่อคุณตั้งค่า ibase = F คุณกำลังตั้งค่าฐานป้อนถึงสิบห้า

ดังนั้นการตั้ง portably ibase ibase=A; ibase=16เพื่อฐานสิบหกจากรัฐที่ไม่รู้จักคุณจึงจำเป็นต้องใช้สองงบ: ibase=16อย่างไรก็ตามในการเริ่มต้นของโปรแกรมที่คุณสามารถพึ่งพามันเป็นทศนิยมและก็การใช้งาน


1: ibase=A; ibase=16เคล็ดลับน่ารักด้วย
Warren Young

นั่นคือ SUSv3 ไม่ใช่ SUSv6 SUSv4 อยู่ที่pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html
Stéphane Chazelas

ฉันมักจะคิดว่า 6 และ 7 ในส่วนหัวเป็นรุ่น ฉันไม่เคยเห็นอะไรที่แตกต่าง - ปัญหา # 1-5 คืออะไร
Random832

@ Random832: SUS และ POSIX ไม่ได้ในสิ่งเดียวกัน
Warren Young

@WarrenYoung ไม่ได้รวม POSIX ไว้ด้วย? ย่อหน้านี้ไม่มีแท็กส่วนขยายและเอกสารระบุว่า "ส่วนหนึ่งของไดรฟ์ข้อมูลของ POSIX.1-2008" นี้ตลอด
Random832

0

ขอแนะนำให้ตั้งค่าibaseและobaseใช้หมายเลขหลักเดียวแทนที่จะเป็นตัวเลขเช่น16เนื่องจากตามbcหน้า man

ตัวเลขหลักเดียวมีค่าเป็นตัวเลขเสมอโดยไม่คำนึงถึงมูลค่าของ ibase

ซึ่งหมายความว่าA,B,...,Fจะมีค่า10,11,...,15ตามลำดับเสมอโดยไม่คำนึงถึงคุณค่าของibaseสิ่งนั้น นอกจากนี้คุณยังสามารถใช้เพื่อระบุจำนวนF+1 16ตัวอย่างเช่นคุณควรเขียน

echo "ibase=F+1; obase=A; C0" | bc

แทนการเขียนecho "ibase=16; obase=A; C0" | bcเพื่อระบุฐานการป้อนข้อมูลที่เป็นฐานการส่งออกเป็น16 10หรือตัวอย่างเช่นถ้าคุณต้องการทั้งคู่ibaseและobaseเป็น 16 คุณควรใช้

ibase=F+1; obase=F+1

ibase=16; obase=10แทนการใช้ ในทำนองเดียวกันถ้าคุณจะป้อนตัวเลขของคุณในฐาน 14 และส่งออกในฐาน 16 ให้ใช้

ibase=E; obase=F+1

แม้ว่ารูปแบบการอาบน้ำจะมีผลลัพธ์เหมือนกัน แต่แบบดั้งเดิมนั้นมีข้อผิดพลาดน้อยกว่าในขณะที่แบบหลังอาจทำให้เกิดความสับสนและข้อผิดพลาดมากขึ้น

ความแตกต่างระหว่างสองรูปแบบโดยเฉพาะอย่างยิ่งจะปรากฏชัดเจนมากขึ้นเมื่อคุณอยู่ในสภาพแวดล้อมการดำเนินการของbcหรือคุณจะเขียนการคำนวณของคุณในไฟล์แล้วส่งไฟล์นั้นไปbcยังอาร์กิวเมนต์ ในสถานการณ์เช่นนี้คุณอาจต้องเปลี่ยนค่าibaseและobaseหลายครั้งและการใช้แบบฟอร์มหลังอาจทำให้เกิดความสับสนและข้อผิดพลาดร้ายแรง (สัมผัสกับมัน)

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