Hiểu rõ về ib ib và những người theo dõi trực tuyến trong trường hợp chuyển đổi với bc?


22

Tôi thường sử dụng bctiện ích để chuyển đổi hex sang thập phân và ngược lại. Tuy nhiên, nó luôn luôn là bản dùng thử bit và lỗi như thế nào ibaseobasenên được cấu hình. Ví dụ ở đây tôi muốn chuyển đổi giá trị hex C0 sang thập phân:

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

Logic ở đây là gì? obase( Atrong ví dụ thứ ba của tôi) cần phải ở cùng một cơ sở với giá trị được chuyển đổi ( C0trong ví dụ của tôi) và ibase( 16trong ví dụ thứ ba của tôi) phải ở trong cơ sở nơi tôi đang chuyển đổi sang?


1
để tính toán hex (đầu vào và đầu ra trong hex) Tôi phải đặt obase trước ibase!
Paschalis

Câu trả lời:


36

Điều bạn thực sự muốn nói là:

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

cho thập phân đến thập phân và:

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

cho thập phân-hex.

Bạn không cần cung cấp cả hai ibaseobasecho bất kỳ chuyển đổi nào liên quan đến số thập phân, vì các cài đặt này mặc định là 10.

Bạn làm cần phải cung cấp cho cả các chuyển đổi như nhị phân-to-hex. Trong trường hợp đó, tôi thấy dễ dàng nhất để hiểu mọi thứ nếu bạn đưa ra obasetrước:

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

Nếu bạn đưa ra ibasetrước thay vào đó, nó sẽ thay đổi cách hiểu của obasecài đặt sau , để lệnh phải là:

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

Điều này là do theo thứ tự này, obasegiá trị được hiểu là số nhị phân, vì vậy bạn cần cung cấp 10000₂ = 16 để có được đầu ra ở dạng hex. Điều đó thật vụng về.


Bây giờ hãy tìm hiểu tại sao ba ví dụ của bạn hành xử như họ làm.

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

    180

    Điều đó đặt cơ sở đầu vào thành 15 và cơ sở đầu ra thành 10, vì giá trị một chữ số được diễn giải bằng hex, theo POSIX . Điều này yêu cầu bccho bạn biết C0₁₅ là gì trong cơ sở A₁₅ = 10 và nó đang trả lời đúng 180₁₀, mặc dù đây chắc chắn không phải là câu hỏi mà bạn muốn hỏi.

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

    C0

    Đây là một chuyển đổi null trong cơ sở 15.

    Tại sao? Đầu tiên, bởi vì Fchữ số đơn được diễn giải bằng hex, như tôi đã chỉ ra trong ví dụ trước. Nhưng bây giờ bạn đã đặt nó thành cơ sở 15, cài đặt cơ sở đầu ra sau đây được hiểu theo cách đó và 10₁₅ = 15, do đó bạn có chuyển đổi null từ C0₁₅ sang C0₁₅.

    Đúng vậy, đầu ra không ở dạng hex như bạn nghĩ, nó ở cơ sở 15!

    Bạn có thể chứng minh điều này với chính mình bằng cách cố gắng chuyển đổi F0thay vì C0. Vì không có Fchữ số nào trong cơ sở 15, hãy bckẹp nó vào E0và đưa ra E0làm đầu ra.

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

    192

    Đây là một trong ba ví dụ duy nhất của bạn có khả năng sử dụng thực tế.

    Nó đang thay đổi cơ sở đầu vào thành hex trước , do đó bạn không còn cần phải đào sâu vào thông số POSIX để hiểu lý do tại sao Ađược hiểu là hex, 10 trong trường hợp này. Vấn đề duy nhất với nó là không cần thiết để đặt cơ sở đầu ra thành A₁₆ = 10, vì đó là giá trị mặc định của nó.


7

Cài đặt ibasenghĩa là bạn cần đặt obasetrong cùng một cơ sở. Giải thích các ví dụ của bạn sẽ cho thấy điều này:

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

Bạn đặt bcđể xem xét các số đầu vào như được trình bày trong cơ sở 15 với "ibase = F". "obase = A" đặt các số đầu ra thành cơ sở 10, là mặc định.

bc đọc C0 dưới dạng số 15 cơ sở: C = 12. 12 * 15 = 180.


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

Trong phần này, bạn đặt đầu vào thành cơ sở 15 và đầu ra thành 10 - trong cơ sở 15, vì vậy cơ sở đầu ra là 15. Đầu vào C0 trong cơ sở 15 là đầu ra C0 trong cơ sở 15.


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

Đặt đầu vào thành cơ sở 16, đầu ra thành cơ sở 10 (A trong cơ sở 16 là 10 trong cơ sở 10).

C0 được chuyển đổi thành cơ sở 10 là: 12 * 16 = 192


Quy tắc cá nhân của tôi là đặt obase trước, để tôi có thể sử dụng cơ sở 10. Sau đó, đặt ibase, cũng sử dụng cơ sở 10.

Lưu ý rằng bccó một ngoại lệ mỉa mai: ibase=Aobase=Aluôn đặt đầu vào và đầu ra thành cơ sở 10. Từ bctrang man:

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

Hành vi này được quy định trong đặc tả của bc: Từ đặc tả Opengroup 2004bc :

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.

Đó là lý do tại sao ibase=Fcài đặt thay đổi cơ sở đầu vào của bạn thành cơ sở 15 và tại sao tôi khuyên bạn luôn luôn đặt cơ sở sử dụng cơ sở 10. Tránh tự gây nhầm lẫn.


@ StéphaneChazelas - Tôi có một hồi ức về "ibase = A" hoạt động trên máy SysVr3 vào năm 1989 hoặc lâu hơn. Tôi cá là nó sẽ quay trở lại xa hơn với Unix Unix Single. Tôi không thể nhanh chóng google lên một ref trước đó.
Bruce Ediger

Tôi nghĩ đó là bởi vì có nhiều liên kết hơn với các thông số kỹ thuật cũ hơn vì chúng đã tồn tại lâu hơn. Điều tương tự cũng xảy ra đối với tài liệu apache / mysql / bugzilla ... trong đó google cung cấp cho bạn tài liệu cho các phiên bản cũ trước thay vì mới nhất.
Stéphane Chazelas

5

Tất cả các số được GNU bc diễn giải là cơ sở đầu vào hiện tại có hiệu lực cho câu lệnh mà số xuất hiện. Khi bạn sử dụng một chữ số bên ngoài đầu vào hiện tại sẽ hiểu chúng là chữ số cao nhất có sẵn trong cơ sở (9 phần thập phân) khi một phần của một số có nhiều chữ số hoặc là giá trị bình thường của chúng khi được sử dụng làm số một chữ số ( A== 10 ở dạng thập phân).

Từ hướng dẫn sử dụng GNU bc :

Các số có một chữ số luôn có giá trị của chữ số bất kể giá trị của ibase . (tức là A = 10.) Đối với các số có nhiều chữ số, bcthay đổi tất cả các chữ số đầu vào lớn hơn hoặc bằng ibase thành giá trị của ibase -1. Điều này làm cho số FFFluôn luôn là số có 3 chữ số lớn nhất của cơ sở đầu vào.

Tuy nhiên, bạn nên lưu ý rằng tiêu chuẩn POSIX chỉ xác định hành vi này cho các bài tập ibaseobase, chứ không phải trong bất kỳ bối cảnh nào khác.

Từ thông số kỹ thuật của SUS trên bc :

Khi ibase hoặc obase được gán một giá trị một chữ số từ danh sách trong Quy ước từ điển trong bc, giá trị sẽ được giả sử theo hệ thập lục phân. (Ví dụ: ibase = A đặt thành cơ sở mười, bất kể giá trị ibase hiện tại .) Mặt khác, hành vi không được xác định khi các chữ số lớn hơn hoặc bằng giá trị của ibase xuất hiện trong đầu vào. Cả ibaseobase sẽ có giá trị ban đầu là 10.

Yếu tố quan trọng bạn đang thiếu là F thực tế không phải là mười sáu, nhưng thực tế là mười lăm, vì vậy khi bạn đang đặt ibase = F, bạn đang đặt cơ sở đầu vào thành mười lăm.

Do đó, để thiết lập một cách hợp lý ibase thành thập lục phân từ trạng thái không xác định, do đó bạn cần sử dụng hai câu lệnh : ibase=A; ibase=16. Tuy nhiên, trong phần đầu của chương trình, bạn có thể dựa vào đó là số thập phân và chỉ cần sử dụng ibase=16.


+1: Thủ thuật dễ thương với ibase=A; ibase=16.
Warren Young

Đó là SUSv3, không phải là SUSv6. SUSv4 có tại pubs.opengroup.org/onlinepub/9699919799/utilities/bc.html
Stéphane Chazelas

Tôi luôn nghĩ rằng 6 và 7 trong các tiêu đề là phiên bản. Tôi chưa bao giờ thấy điều gì khác biệt - vấn đề # 1-5 là gì?
Random832

@ Random832: SUS và POSIX không giống nhau .
Warren Young

@WarrenYoung Không kết hợp POSIX? Đoạn này không có thẻ mở rộng và tài liệu nói những điều như "một phần của tập POSIX.1-2008" này xuyên suốt.
Random832

0

Luôn luôn được khuyến nghị đặt ibaseobasesử dụng một số có một chữ số, thay vì một số như 16, vì theo bctrang man,

Các số có một chữ số luôn có giá trị của chữ số bất kể giá trị của ibase.

Điều này có nghĩa là A,B,...,Fluôn có các giá trị 10,11,...,15tương ứng, bất kể giá trị của ibaselà gì. Bạn cũng có thể sử dụng F+1để chỉ định số 16. Ví dụ, bạn nên viết tốt hơn

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

thay vì viết echo "ibase=16; obase=A; C0" | bcđể xác định rằng cơ sở đầu vào là 16và cơ sở đầu ra là 10. Hoặc ví dụ: nếu bạn muốn cả hai ibaseobase16 tuổi, bạn nên sử dụng tốt hơn

ibase=F+1; obase=F+1

thay vì sử dụng ibase=16; obase=10. Tương tự, nếu bạn định nhập số của mình vào cơ sở 14 và xuất chúng ở cơ sở 16, hãy sử dụng

ibase=E; obase=F+1

Mặc dù các hình thức tắm có kết quả tương tự, nhưng hình thức trước ít bị lỗi hơn, trong khi hình thức sau có thể dẫn đến nhiều nhầm lẫn và lỗi.

Sự khác biệt giữa hai biểu mẫu đặc biệt trở nên rõ ràng hơn, khi bạn ở trong môi trường thực thi bchoặc bạn sẽ viết các phép tính của mình trong một tệp, sau đó chuyển tệp đó thành bcđối số. Trong các tình huống như vậy, bạn có thể phải thay đổi các giá trị ibaseobasenhiều lần, và sử dụng biểu mẫu sau, có thể dẫn đến nhầm lẫn và lỗi nghiêm trọng. (trải nghiệm nó)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.