Convertを使わずに2進数、10進数の相互変換を行う - C#

通常ならこのような変換には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クラスを使う方が無難ですよね。

一つの発見はToInt32ToInt64では処理速度に差がある、ということでした。

1 Comments:

匿名 さんのコメント...

恐らく、速度についてはstringを使ってるのもあると思いますね。
ToInt32とToInt64は、内部で上下入れ替えとかしてそう(まだじっくり見てない)

Sony Style(ソニースタイル)
デル株式会社

Recent Posts