ムイ

もはやクライミング日記

irbを電卓として使用する

結論

暗算の苦手な人は、irbが電卓として便利に役立ちます。

irb以外の、他の対話型スクリプト言語環境でも同じ)

過程

(一応)組込みプログラマーとして仕事をしていると、10進数から16進数への変換、16進数から10進数への変換というのをしばしば行う。

レジスタに値を入れたり、単体テストのためにそれっぽい値を用意したり。

レジスタへの値の設定、確認などは大体ビット単位で意味が決まっているので、2進数を使ったりもする。

慣れていけば頭のなかで計算も可能なのだけれど、算数が元から得意じゃなく、暗算も苦手な自分はいつも関数電卓の変換機能を使っていた。

これが実に面倒くさい。

 

rubyの関数の挙動を調べるためにirbを使っていたところ、これで計算、変換したらよくね? ということに気付いた。

環境

自分は家でも仕事でもWindowsなので、Cygwin + ruby 1.9.3を使用している。

irbのバージョンは 0.9.6(09/06/30)。

ずいぶん古く感じるけれど、基本的な機能しか使用しないので問題ないはず。

10進数を16進数に変換

例1 10進数8111を16進数に変換する

irb(main):001:0> 8111.to_s(16)

=> "1faf"

例2 10進数8111を0付き8桁の16進数に変換する

irb(main):002:0> format("%08x", 8111)

=> "00001faf"

数値クラスのものを16進数に変換する方法、整え方は様々。

細かい話は下記リンクを見れば概ね問題なし。

逆引きRuby - 数値

sprintf フォーマット

自分はsprintfという字面があまり好きではないので、formatをよく使う。好みの問題。

16進数を10進数に変換

例1 16進数0xdeadbeefを10進数に変換する

irb(main):003:0> 0xdeadbeef

=> 3735928559

何もしなくてもいい。irbの標準出力は自動で10進数に変換してくれる。

あえて文字列するなら、下記のように

例2 16進数の0xfacefeedを10進数の文字列オブジェクトに変換する

irb(main):004:0> 0xfacefeed.to_s(10)

=> "4207869677"

2進数を10進数に変換

例1 2進数11010001を10進数に変換する

irb(main):006:0> 0b11010001

=> 209

これも前述同様に変換は不要。基本、10進数への変換には値を入力してエンターキーを押すだけで、何もする必要がない。

ちょっとしたビット演算、計算をする

例1 0xbabaを2ビットシフトして8桁の16進数を求める

irb(main):007:0> format("%08x", (0xbaba << 2))

=> "0002eae8"

formatを入力するのが手間なら、単純に下記でかまわない。あとから0を自分で補う。

irb(main):009:0> (0xbaba << 2).to_s(16)

=> "2eae8"

例2 0xddcdの7ビット目を反転した16進数を求める

irb(main):011:0> (0xddcd ^ (1 << 6)).to_s(16)

=> "dd8d"

「7ビット目の反転」に用いるXORの対象は「1を6ビット左シフトしたもの」であることに注意。頭が回らない時なら、素直にこういうこともできる。

irb(main):012:0> (0xddcd ^ 0b01000000).to_s(16)

=> "dd8d"

数え間違えるケースがあるので、こっちはこっちで注意が必要ではある。

例3 10進数842の16ビット幅における2の補数を16進数で求める

irb(main):013:0> ((~842 & 0xffff) + 1)

=> 64694

irb(main):014:0> ((~842 & 0xffff) + 1).to_s(16)

=> "fcb6"

もしかすると補数の求め方には、もっと便利な関数が存在するのかもしれない。

ここでは情報処理の基礎に則って、「反転したのち+1」というオーソドックスな計算方法で求めている。

例3のような処理はいつ役立つのか。具体的に言うと18ビット幅の分解能を持つデルタシグマ式のADCをバイポーラ設定で用いるときなどに役立つ。こういった値を求めるのはなかなか手間なので、irbの真価が発揮されるように感じる。

例4 10進数8675の18ビット幅における2の補数を16進数で求める

irb(main):018:0> ((~8675 & 0x3ffff) + 1).to_s(16)

=> "3de1c"

こういう時は、怖いので念のため検算をすることがある。精神安定剤に近い。

irb(main):022:0> a = ((~8675 & 0x3ffff) + 1).to_s(16)

=> "3de1d"

irb(main):023:0> (a.hex + 8675).to_s(16)

=> "40000"

2の補数なので、足しあわせて18bit幅の範囲ですべて0になれば問題ない。

上記のように変数を使うのも有効的だ。.hexは16進数の文字列オブジェクトを数値オブジェクトに変換している。

複雑な変換、あるいは計算には変数を用いるのは効果的だが、対話型の場合どこに何が入っているのか、どの変数が何を意味しているのか忘れることもあるので、やり過ぎに注意。

 

 以上、チラ裏。