[Haskell] 10進数からN進数への変換処理

[Haskell] 10進数からN進数への変換処理

Haskellのお勉強

今日もHaskellの勉強がてら10進数からN進数(1..16進数)への変換処理を書いてみようと思います。関数に変換する数値と、何進数に変換するかの数値を渡すと、変換された文字列がかえってくるイメージです。

早速ですがHaskellのコードです。N進数の適当な言葉が英語で見つからなかったのでNStringとしました。

Haskellのコード

intToNString :: Int -> Int -> String
intToNString x n
    | n == 0 = []
    | n == 1 = replicate x '1'
    | n <= 16 = getNString x n
    | otherwise = []
    where
        getNString :: Int -> Int -> String
        getNString x n
            | x == 0 = []
            | otherwise = (getNString (x `div` n) n) ++ (numbers !! (x `mod` n))
            where numbers = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"]

アルゴリズムと処理の流れ

10進数からN進数への変換は変換したい数をNで割ることを繰り返すことで求められます。ですのでそれを再帰的に繰り返し、余りを連結させるだけです。 具体的な値で確認してみます。

10進数の13を2進数に変換する場合、13を2で割り算し、商1以上の場合は更に商を2で割ることを繰り返します。

  • 13 / 2 = 6 余り 1
  • 6 / 2 = 3 余り 0
  • 3 / 2 = 1 余り 1
  • 1 / 2 = 0 余り 1

商が0になったら計算終了で、計算時に出た余りを最後のものから順に(下から順に)つなげた値が2進数の値です。

よって、10進数の13 = 2進数の1101 となります。

N進数への変換でも同じ処理の流れとなります。 ただし、11進数以上になると、アルファベットa..fが11..16を表すことになるので、その変換処理も必要になります。

さらに例外として、1進数は1を繰り返すだけとします。

コードの解説

まず今回扱うのは整数値を1..16進数の文字列への変換なので、1..16以外のN進数が指定された場合は空文字を返します。

それから商が0になるまで再帰処理を行い余りを連結させていきます。

連結させる余りを変換するための0..fまでの16の文字列を予めリストとして用意しておき、そのリストから余りを要素番号として取り出した文字をN進数1桁の文字として置き換えます。
例えば余りが0の場合は0番目の要素”0″、余り15の場合は15番めの要素”f”に置き換えます。

置き換える対象の文字が文字列のリストとなっているのは、連結させる時にリスト同士である必要があるためです。

アルファベット全部を使えば、0..9a..fで36進数までは拡張して対応できるはずです。

C#でも書く

例によってC#でのコードです。再帰処理ではなくループで処理しています。
余りを上から順に連結させて、最後にLINQで反転させています。

public static string IntToNString(int x, int n)
{
    var nstring = "";
    var numbers = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
    int r = 1;  // 余り
    int q = x;  // 商

    // 商が0になるまでループ
    while (q > 0)
    {
        r = q % n;
        nstring += numbers[r];
        q = q / n;
    }
    return string.Join("",nstring.Reverse());
}

Haskellカテゴリの最新記事