16進数を10進数に、またはその逆に変換するには、bc
ユーティリティをよく使用します。ただし、ibase
とobase
の設定方法は常に試行錯誤です。たとえば、ここでは16進値C0を10進数に変換したいと思います。
$ 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
(3番目の例ではA
)は、変換される値と同じベースにある必要があります(C0
(私の例では)およびibase
(16
3番目の例では)変換先のベースにある必要がありますか?
あなたが実際に言いたいのは:
$ echo "ibase=16; C0" | bc
192
16進数から10進数、および:
$ echo "obase=16; 192" | bc
C0
10進数から16進数の場合。
これらの設定のデフォルトは10であるため、10進数を含む変換ではibase
とobase
の両方を指定する必要はありません。
doは、バイナリから16進数への変換など、両方の変換を行う必要があります。その場合、最初にobase
を指定すると、意味がわかりやすくなります。
$ echo "obase=16; ibase=2; 11000000" | bc
C0
代わりにibase
を最初に指定すると、次のobase
設定の解釈が変更されるため、コマンドは次のようになります。
$ echo "ibase=2; obase=10000; 11000000" | bc
C0
これは、この順序でobase
値が2進数として解釈されるため、16進数で出力を取得するには10000₂= 16を指定する必要があるためです。それは不器用です。
では、3つの例がそれぞれの動作をする理由を調べてみましょう。
echo "ibase=F;obase=A;C0" | bc
180
1桁の値は16進数で解釈されるため、入力ベースを15に、出力ベースを10に設定します POSIXによると 。これはbc
に、ベースA₁₅= 10にあるC0 whatが何であるかを教えてくれ、そして180 correctlyと正しく答えていますが、これは確かにあなたが尋ねようとした質問ではありません。
echo "ibase=F;obase=10;C0" | bc
C0
これは、基数15のnull変換です。
どうして?まず、前の例で指摘したように、単一のF
桁は16進数で解釈されるためです。しかし、これをベース15に設定したので、次の出力ベース設定はそのように解釈され、1015 = 15なので、C0₁₅からC0₁₅へのヌル変換があります。
そうです、あなたが想定していたように、出力は16進数ではなく、ベース15です!
F0
の代わりにC0
を変換してみると、これを自分で証明できます。基数15にはF
の数字がないため、bc
はそれをE0
に固定し、E0
を出力として提供します。
echo "ibase=16; obase=A; C0"
192
これは、実際に使用される可能性が高い3つの例のうちの唯一の例です。
入力ベースを16進数firstに変更しているため、A
がなぜであるかを理解するためにPOSIX仕様を詳しく調べる必要はありません。 16進数として解釈されます。この場合は10です。これの唯一の問題は、デフォルト値であるため、出力ベースをA₁₆= 10に設定することが冗長であることです。
ibase
を設定すると、同じベースにobase
を設定する必要があります。あなたの例の説明はこれを示します:
echo "ibase=F;obase=A;C0" | bc
bc
を設定して、「ibase = F」を使用して、基数15で表される入力数値を考慮します。 "obase = A"は、出力数を10進数に設定します。これがデフォルトです。
bc
は、C0を基数15の数値として読み取ります。C=12。12* 15 = 180。
echo "ibase=F;obase=10;C0" | bc
この例では、入力を底15に設定し、出力を底15で10に設定しているため、出力底は15です。底15のC0入力は底15のC0出力です。
echo "ibase=16;obase=A;C0" | bc
入力を底16に設定し、出力を底10に設定します(底16のAは底10の10です)。
ベース10に変換されたC0は、12 * 16 = 192です。
私の個人的なルールは、base 10を使用できるように、最初にobaseを設定することです。次に、base 10を使用してibaseを設定します。
bc
には皮肉な例外があることに注意してください:ibase=A
およびobase=A
は常に入力と出力を10進数に設定します。bc
のマニュアルページから:
Single digit numbers always have the value of the digit
regardless of the value of ibase.
この動作はbc
の仕様に規定されています: 2004 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を使用して常にベースを設定することをお勧めした理由。混乱を避けてください。
すべての数値は、GNU bcによって解釈されます。ステートメントに有効な現在の入力ベースとしてbcが表示されます。現在の入力の外の数字を使用する場合は、複数桁の数値の一部の場合は基数(10進数で9)、または1桁の数値として使用される場合は通常の値(10進数ではA
== 10)。
GNU bcマニュアル から:
ibaseの値に関係なく、1桁の数字は常に数字の値を持ちます。 (つまり、A = 10)。複数桁の数値の場合、
bc
はibase以上のすべての入力桁をibase-1の値に変更します。これにより、数値FFF
は常に入力ベースの最大3桁の数値になります。
ただし、POSIX標準ではibase
およびobase
への割り当てについてのみこの動作が定義されており、他のコンテキストでは定義されていないことに注意してください。
bcのSUS仕様 から:
ibaseまたはobaseに単一のdigitbcの字句表記法のリストからの値。値は16進数で想定されます。 (たとえば、ibase= Aは、現在のibase値。)それ以外の場合、ibaseの値以上の数字が入力にある場合の動作は未定義です。 ibaseとobaseの両方の初期値は10です。
欠けている重要な要素は、Fは実際には16ではなく、実際には15であるため、ibase = Fを設定する場合は、入力ベースを15に設定します。
したがって、ibaseを不明な状態から16進数に移植可能に設定するには、ibase=A; ibase=16
という2つのステートメントを使用する必要があります。ただし、プログラムの最初では、10進数であることを前提として、単にibase=16
を使用できます。
ibase
のマニュアルページによれば、_16
_などの数値ではなく、1桁の数値を使用してobase
およびbc
を設定することを常にお勧めします。
1桁の数字は、ibaseの値に関係なく、常に数字の値を持ちます。
つまり、ibase
の値に関係なく、_A,B,...,F
_の値は常に_10,11,...,15
_になります。 _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
_
バスフォームでも同じ結果が得られますが、前者はエラーが発生しにくく、後者は混乱とエラーを引き起こす可能性があります。
2つの形式の違いは、bc
の実行環境にいる場合、または計算をファイルに書き込み、そのファイルを引数としてbc
に渡す場合に特に顕著になります。このような状況では、ibase
とobase
の値を数回変更する必要があり、後者の形式を使用すると、深刻な混乱とエラーが発生する可能性があります。 (体験する)