中年プログラマーの息抜き

カシマルです。 最近、新しい土地へ引っ越しをしたのですが、これを機に何か始めたいなと思ってブログをはじめました。気の向くままに更新していきます。

コンピュータ:負数と補数:2の補数を理解する

はじめに

多くのコンピュータでは一般的に負数は2の補数で表現されているようで、その理由の一つには減算を加算として扱えるようになることがあるみたいです。その方が良いみたいです。こういうの・・演算装置(CPU的な)の話かな・・ 今回はこの2の補数表現に注目して整理します。

-> 1の補数:ビット反転
-> 2の補数:1の補数+1

表現できる範囲

先頭ビットで、その値が、正(0)なのか or 負(1)なのかを表現する。(その値の大きさには影響しない)

nビットであれば:-2n-1 ~ 2n-1-1

int型(32ビット)であれば:-231 ~ 231-1:-2,147,483,648 ~ 2,147,483,647

実用例を用いた検証

前の記事で扱った内容を用いて確認してみます

Java実装:カラーコードの定義

    "ピーコック", 0xFF46D6DB
    "ミカン", 0xFFFFB878
    "バナナ", 0xFFFBD75B
    "バジル", 0xFF51B749
    "セージ", 0xFF7AE7BF
    "ブルーベリー", 0xFF5484ED
    "ラベンダー", 0xFFA4BDFC
    "ブドウ", 0xFFDBADFF
    "フラミンゴ", 0xFFFF887C
    "グラファイト", 0xFFE1E1E1

Swift実装:カラーコードの定義

    "ピーコック": -12134693
    "ミカン": -18312
    "バナナ": -272549
    "バジル": -11421879
    "セージ": -8722497
    "ブルーベリー": -11238163
    "ラベンダー": -5980676
    "ブドウ": -2380289
    "フラミンゴ": -30596
    "グラファイト": -1973791
16進数->2進数->1の補数->2の補数->絶対値->10進数
"ピーコック":10進数
16進数:FF46D6DB
2進数:11111111010001101101011011011011
-> 1の補数:00000000101110010010100100100100
-> 2の補数:00000000101110010010100100100101
-> 絶対値:12134693
-> 10進数:-12134693

 

"ミカン":10進数
16進数:FFFFB878
2進数:11111111111111111011100001111000
-> 1の補数:00000000000000000100011110000111
-> 2の補数:00000000000000000100011110001000
-> 絶対値:18312
-> 10進数:-18312

 

"バナナ":10進数
16進数:FFFBD75B
2進数:11111111111110111101011101011011
-> 1の補数:00000000000001000010100010100100
-> 2の補数:00000000000001000010100010100101
-> 絶対値:272549
-> 10進数:-272549
マスク表現でRBGを確認
extension UIColor {
    static func create(hex: Int) -> UIColor {
        return UIColor(
            displayP3Red: CGFloat((hex & 0xFF0000) >> 16) / 255.0
            , green: CGFloat((hex & 0xFF00) >> 8) / 255.0
            , blue: CGFloat(hex & 0xFF) / 255.0
            , alpha: 1.0
        )
    }
}
"ピーコック":(FF46D6DB )ARGB値
R値(赤):hex & 0xFF0000
-> 16進数:FF46D6DB (hex)
-> マスク:00FF0000 (0xFF0000)
-> 演算値:00460000 (FF46D6DB & 00FF0000)
-> シフト:0x46 (00460000>>16)
-> 10進数:70
G値(緑):hex & 0xFF00
-> 16進数:FF46D6DB (hex)
-> マスク:0000FF00 (0xFF00)
-> 演算値:0000D600 (FF46D6DB & 0000FF00)
-> シフト:0xD6 (0000D600 >>8)
-> 10進数:214
G値(青):hex & 0xFF
-> 16進数:FF46D6DB (hex)
-> マスク:000000FF (0xFF)
-> 演算値:000000DB (FF46D6DB & 000000FF)
-> シフト:0xDB (000000DB >>0)
-> 10進数:219

まとめ

Java実装とSwift実装で同じ定義という検証をしました。上の定義も計算違いなどで軽微な間違いがあるかもしれません、もしそうでも、ここではそれは置いておくとして(-_-;)、個人見解「根拠説明できる実装」が大切、基本だし・・まあ理想かなと・・。