通常ならこのような変換にはSystem.Convert
を使うだろうが、これを使わずに変換を行う処理を自身で書いてみたくなった。
.NET Frameworkに勝るモノを自身で書ける、などとは思わないが、デモンストレーション的な感じでね。
10進数 → 2進数
例えば、10進数から2進数への変換は以下のように行う。string bin = Convert.ToString(22, 2);//10110
これを自身で実装してみる。
色々書いてみたが、結局ビット演算を使うのが一番速いし、コードもシンプルになる。
Example
/// <summary> /// 10進数を2進数文字列に変換します。 /// </summary> /// <param name="dec">10進数</param> /// <returns>2進数文字列</returns> static string DecimalToBinaryString(long dec) { string ret = string.Empty; for (; dec > 0; dec >>= 1) { ret = (dec & 1) + ret; } return ret; }
dec & 1
で右端のビットのみを取得している。右端のビットを取得したら変数
dec
右へビットシフトする。変数
dec
を追っていくと以下のようになる。//引数:22 dec: 22(10110) dec: 11(01011) dec: 5(00101) dec: 2(00010) dec: 1(00001) dec: 0(00000)このようにしてビットを一つづつ取得して文字列にしている。
処理速度は?というと
Convert
クラスと比較して約8倍掛る結果となった。ん~... 使えね~(^_^;)
2進数 → 10進数
Convert
クラスを使用して2進数文字列から10進数への変換は以下のように行う。long dec = Convert.ToInt64("10110", 2);//22
これを実装してみる。
Example
/// <summary> /// 2進数文字列を10進数(long)に変換します。 /// </summary> /// <param name="bin">2進数文字列</param> /// <returns>10進数</returns> static long BinaryToDecimalNumber(string bin) { long ret = 0; foreach (var chr in bin) { ret = (ret << 1) | ((long)chr & 1); } return ret; }文字を一つづつ取り出して足していくのですが、ここでもビット演算が処理を簡単にしてくれる。
コード内の「
(long)chr & 1
」を説明すると、string
型から文字を一つづつchar
型として取りだしたモノがchr
になりますが、これを数値型(long
)にキャストし、そして右端のビットのみを取得しています。Type:Char 0 = Ascii:48 binay:110000
Type:Char 1 = Ascii:49 binay:110001
コード内の「
ret << 1
」は先程説明した値chr
を常に右側のビットとして足していくので、既存の値を左へシフトして一番右側のビットを開けてやっているワケです。処理の過程を表すと以下のようになる。
//引数:"10110" 0(00000) + 1 = 1(00001) 2(00010) + 0 = 2(00010) 4(00100) + 1 = 5(00101) 10(01010) + 1 = 11(01011) 22(10110) + 0 = 22(10110)
これを
Convert
クラスを使用した場合の処理速度と比較してみる。1000 * 1000回処理を行う際に掛った時間
//引数:"10110"(22) Convert.ToInt32 : 112ms Convert.ToInt64 : 174ms BinaryToDecimalNumber : 80ms
何故か私が書いたモノのが一番速かったのだが、私の書いたモノには欠点がある。
それは1以上の値しか扱えないこと。つまり「0」もダメ。
しかし
Convert
クラスなら負の数も扱えるのでこちらの方が優秀。扱う値の範囲が分かっているなら、私の書いたモノを使っても問題ない場合もあるだろうが、やはり
Convert
クラスを使う方が無難ですよね。一つの発見は
ToInt32
とToInt64
では処理速度に差がある、ということでした。
1 Comments:
恐らく、速度についてはstringを使ってるのもあると思いますね。
ToInt32とToInt64は、内部で上下入れ替えとかしてそう(まだじっくり見てない)
コメントを投稿