基数変換

逆転したビット列です。

2進数にしてreverseして10進数に戻しています。

import Data.Char
import Numeric

main = do print $ rbits 4
          print $ rbits 5

rbits :: Int -> [Int]
rbits n = map (\m -> readBin $ reverse $ padding0 n (toBin m)) $ take (2 ^ n) [0..]

toBin :: Int -> String
toBin n = showIntAtBase 2 intToDigit n ""

padding0 :: Int -> String -> String
padding0 n xs = replicate (n - length xs) '0' ++ xs

readBin :: String -> Int
readBin = fst.head.(readInt 2 (`elem` "10") digitToInt)

用意されている基数変換の関数を使ってみました。まずは2進数への変換。なのですが2進数へ変換する関数がなかったのでまずは16進数へ変換する関数から出発。

Prelude> Numeric.showHex 100 "(16)"
"64(16)"

showHexがどうなっているかを見てみるとこうなっていました。

showHex = showIntAtBase 16 intToDigit

これを基に2進数への変換関数を作成。

Prelude> (Numeric.showIntAtBase 2 Data.Char.intToDigit) 100 "(2)"
"1100100(2)"

今度は2進数から10進数に変換する関数です。こちらも2進数から変換するものがなかったので16進数からスタート。

Prelude> Numeric.readHex "FF"
[(255,"")]

タプルのリストになっているので欲しいところだけ残します。

Prelude> (fst.head.Numeric.readHex) "FF"
255

readHexがどうなっているかを見てみるとこうなっていました。

readHex = readInt 16 isHexDigit digitToInt

ということで書き換え。

Prelude> (fst.head.(Numeric.readInt 16 Data.Char.isHexDigit Data.Char.digitToInt)) "FF"
255

これを基に2進数版の変換関数を作成。

Prelude> (fst.head.(Numeric.readInt 2 (`elem` "01") Data.Char.digitToInt)) "1111"
15

以下は同じような考え方で作ったPerl版。

use strict;
use warnings;

print join(',', rbits(4)), "\n";
print join(',', rbits(5)), "\n";

sub rbits {
  my $keta = shift;
  return map {oct "0b" . reverse sprintf "%0*b", $keta, $_} (0 .. 2 ** $keta - 1);  
}