数値・単位・ビット
同じffなのに255と-1になるのはなぜ?
使うツール
同じバイトを読んだはずなのに、片方のログでは255、もう片方では−1。転送中にデータが壊れたと疑う前に、符号付きと符号なしの違いを確認してみます。FFという二桁は8個のビットがすべて1であることを示しますが、それをどんな整数として読むかまでは決めません。ビット演算で幅と符号をそろえると、値が変わった場合と、同じ並びを違う規則で読んだ場合を切り分けられます。
まずは8ビットの符号なしとして読む
11111111 (binary)
ff (hexadecimal)
255 (unsigned decimal)ビット演算で幅8、符号なし、入力基数16、演算ORを選び、FFと0を入力します。OR 0はビットを変えないため、結果の10進数255、二進数11111111、16進数ffを読み比べられます。入力基数を10のままFFと入力すると数値として読めません。文字列に見える桁を、どの基数として解釈するかも条件の一部です。
8ビットの符号なし整数は0〜255です。256を入れるには9ビット必要であり、8ビットの同じ枠へそのまま入りません。整数型の範囲ツールで幅8を調べ、最大値と照合すると、入力エラーが出た理由を桁数から説明できます。255を特別な文字として覚えるより、2の8乗から1を引いた上限として理解すると、16ビットや32ビットにも応用できます。
−1を入力し、ビット列が同じになることを確かめる
255 − 256 = −1
11111111 → −1 (signed)
11111111 → 255 (unsigned)次は幅8、符号あり、入力基数10、ORのまま、−1と0を入力します。10進表示は−1でも、符号なしの値は255、ビット列は11111111です。二の補数では最上位が1のとき、符号なしで読んだ値から2のビット幅乗を引いて解釈します。この例では255−256なので−1です。先頭の1だけを負号へ置き換えて残りを127と読む方式ではありません。
同じ幅8でも、符号ありの入力範囲は−128〜127です。符号ありの状態でFFを16進数として入力すると、既定の範囲外拒否では255として範囲を超えます。ビット列を確認するために入力範囲を切り捨てる設定もありますが、それは明示的な別の操作です。単に符号を変更しただけで、どんな入力も都合よく再解釈されると考えないでください。
FFとFFFFでは、枠の大きさが違う
0000000011111111 = 255
1111111111111111 = −1 (signed 16-bit)
NOT 0, unsigned 8-bit → 255
NOT 0, unsigned 16-bit → 6553516ビットの00FFは最上位が0なので、符号ありでも255です。16ビットで−1を表すのはFFFFです。8ビットの−1を16ビットでも−1として保つには、負数の上位を1で埋める符号拡張という考え方が必要です。単に左へ0を付けたら、元の負数の意味までは保てません。通信仕様で1バイトか2バイトかを読むことは、表示の桁数以上の意味を持ちます。
NOT 0を幅8と幅16で試すと、反転する桁の数が違うため結果が255と65535に分かれます。このツールは指定した幅へ結果を収めます。JavaScriptのNumberに対するビット演算など、実行言語の暗黙の幅がある処理と比較するときも、同じ前提をそろえる必要があります。大きな整数を扱えることと、固定幅の規則を省略できることは別です。
負数の右シフトは、空いた桁の埋め方を見る
11111110 → 01111111 (logical) = 127
11111110 → 11111111 (arithmetic) = −1幅8、符号あり、10進数−2を入力し、右シフトを1にします。論理右シフトは左を0で埋めるため127、算術右シフトは符号のビットを保つため−1です。『右へ一つだから必ず半分』という説明だけでは、この違いを見落とします。ネットワークのビット列をずらしたいのか、符号付き整数を扱いたいのかを先に決めてから方式を選びます。
切捨てはエラーを隠す設定にしない
8ビットの枠で256を切り捨てると、残る下位8ビットは0です。入力できたように見えても、256が0へ変わっています。範囲外拒否はこうした情報損失を止めるための設定です。バイナリ仕様に折返しや下位ビットだけを使う規則があると確認できた場合に、初めて切捨てを選びます。都合のよい結果が出るまで幅や符号を切り替える使い方では、原因の説明にはなりません。
確認結果には、元の文字列FF、入力基数16、幅8、符号の有無を残します。さらに複数バイトの並びを扱うなら、バイト順も元の仕様で確認します。この画面で整数の読み方を合わせたことだけで、ファイルのバイト順や通信の項目境界まで正しいと証明したことにはなりません。同じ条件をそろえた後にも値が違うなら、その時点で取り出したデータ自体を比較します。