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());
}
コメントを書く