challenge LL Golf Hole 6 - 10進数を2進数に基数変換する

与えられた10進数の整数を2進数に変換してください。ただし、与えられる整数は0以上とします。

与える整数についてはリテラルで与える、標準入力で与える、引数で与えるなどは自由とします。

余力のあるものはこのプログラムを短くしてみたり、さまざまな基数への変換に対応させてみてください。

※LL Future実行委員の高野光弘です。この出題は LL Future公式の出題であり、優れたものについてはLL Golfのセッションでご紹介させていただくかもしれません。ご理解の上、ご投稿ください。また、LL Futureのチケットは現在も発売中です。よろしければ、メインイベントの方にもぜひご参加ください。

1
2
# 標準入力から整数を受け取る
ruby -e 'puts gets.to_i.to_s(2)'

Posted feedbacks - Nested

Flatten Hidden

2進に限定すればprintfを用いるのが簡単に見える。 n進は例から縮まないorz

1
ruby -e'printf "%b",gets'
#7221 のやり方のまま、表現だけ変えて9byteまで縮めてみた
1
p "%b"%$*

pと"の間のスペースは削れますね

1
p"%b"%$*

標準入力から基数、数値の順で。基数は 36 までです。

1
(format t"~VR"(read)(read))
2進数の場合
1
(format t "~b" (read))

pure bash。引数。2進数のみ。

bashのprintfだと%bが使えないようなので、8進数経由で。

1
2
3
4
5
6
a=(000 001 010 011 0100 0101 110 111)
n=`printf '%o\n' $1`
while [ "$n" != '' ];do
  echo -n ${a[${n:0:1}]}
  n=${n:1}
done
楽をするならこんなのはどうでしょう。

  e.g.
    $ echo "obase=2; 255" | bc
    11111111

# AIX 4.3.3.0, HP-UX B.11.00, Linux 2.4.2, SunOS 5.5.1で動作を確認。
どのシステムでも動くようにするなら、Bourne shellで愚直に。

  e.g.
    $ dec2bin() {
      d=$1
      t=''
    
      [ $# -eq 0 ] && return 1
    
      while [ $d -gt 0 ]; do
        r=`expr $d % 2`
        d=`expr $d / 2`
        t="$r$t"
      done
    
      echo "${t:=0}"
    
      return 0
    } && dec2bin 255

# AIX 4.3.3.0, HP-UX B.11.00, Linux 2.4.2, SunOS 5.5.1で動作を確認。

なるほど。

で、POSIX Shell規格でしたらexprを呼ばずにいけるので、ちょっとだけ改造してみました。

1
2
3
4
5
d=$1
while [ $d -gt 0 ];do
  echo -n $(($d%2))
  d=$(($d/2))
done

間違い、桁が逆でした。

1
2
3
4
5
6
d=$1
while [ $d != 0 ];do
  t=$(($d%2))$t
  d=$(($d/2))
done
echo $t

コマンドライン引数から整数、基数を受け取る

1
2
python -c 'import sys;print int(sys.argv[1], int(sys.argv[2]))' 1010 2
# 出力 -> 10
お題は10進数から2進数(n進数)への変換です。

対話形式で整数、基数を受け取る

1
2
3
python -c 'n,m=raw_input().split();print int(n, int(m))'
# 入力 -> 1010 2
# 出力 -> 10

2進数限定、桁数固定です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <bitset>
#include <iostream>

int main(int, char* [])
{
    int n;
    std::cin >> n;
    std::cout << std::bitset<32>(n) << std::endl;

    return 0;
}

標準入力から数値・基数の順で。 R5RS だと基数は 2, 8, 10, 16、 Gauche だと 2〜36 です。

1
(print(number->string(read)(read)))

Scheme だと引き数の評価順序が規定されていないのでこっちの方が行儀がいいかな。入力は基数・数値の順に。

1
(let1 n(read)(print(number->string(read)n)))

標準入力から受け取った10進の整数を 2進数に変換します。 125B

1
2
3
4
5
class B{
    public static void main(String[]s){
        System.out.println(Long.toString(new java.util.Scanner(System.in).nextInt(),2));
    }
}

Squeak Smalltalk で。

1
10 radix: 2   "=> '1010' "
コマンドライン入力でオプション付きにしました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env gosh
(define output
  (lambda (num base)
    (print (number->string (x->number num)(x->number base)))))

(define (main args)
  (let ((n (length args)))
    (cond
      ((= n 1)
         (display (car args))
         (print " number [base-number(2~36)]"))
      ((= n 2)
        (cond 
          ((< (x->number (cadr args)) 0) (print "number error(-)"))
          (else (output (cadr args) 2))))      
      ((or (< (x->number (caddr args)) 2) (> (x->number (caddr args)) 36))
         (print "base-number error(2~36)"))
      (else (output (cadr args) (caddr args))))))

出力フォーマットにこだわらなければintToBts()だけで変換可能です。

1
d2b <- function(n) paste(as.integer(rev(intToBits(n:n))), collapse="")
標準入力から、数値、基数(2,8,10,16)の順で。
1
2
3
4
5
6
7
8
9
using System;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(Convert.ToString(int.Parse(Console.ReadLine()), int.Parse(Console.ReadLine())));
    }
}
お題(10進数 -> 2進数)を読み違えてた。。。
#7226, #7227のやつは、2進数 -> 10進数 だった。

なので改めて考えてみる。
文字列フォーマットでは8進数と16進数しかないので(多分)

  #10進数を8進数に
  python -c 'print "%o" % 64' #=> '100'
  #10進数を16進数に
  python -c 'print "%x" % 256' #=> '100'

2~36進数に対応するように書いてみた。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 10進数を2~36進数に変換
def f(n, m):
    t = '0123456789abcdefghijklmnopqrstuvwxyz'
    if not 2 <= m <= len(t): return 'error'
    if n == 0: return '0'
    r = []
    while n > 0:
        r.append(t[n % m]); n /= m
    return ''.join([i for i in reversed(r)])

f(4, 2) #=> '100'
f(64, 8) #=> '100'
f(256, 16) #=> '100'
f(1024, 32) #=> '100'

再帰バージョン

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
'''
>>> f(0, 0)
'0'
>>> f(4, 2)
'100'
>>> f(64, 8)
'100'
>>> f(256, 16)
'100'
>>> f(1024, 32)
'100'
'''

def f(dec, base):
  digit = '0123456789abcdefghijklmnopqrstuvwxyz'
  d, m = divmod(dec, base)
  if d:
    return f(d, base) + digit[m]
  else:
    return digit[m]

if __name__ == '__main__':
  import doctest
  doctest.testmod()
1
perl -e "printf('%b', $ARGV[0])"
stdin -> stdout
1
(format #t"~b"(read))
stdin -> stdout
1
print 0L.toString("$System.in".toLong(),2)

shimakumaさんに比べると、ちょっと長いですね・・

1
2
def input = System.in.newReader().readLine()
println Integer.toBinaryString(input.toInteger())

old awkです。何の芸もありませんが。

1
2
3
4
5
6
7
8
9
#!/bin/awk -f
{
n=$1
a=n%2
while((n=int(n/2))>0)
        a= (n%2) a
print $1 "->" a

}

短くする楽しみが全く無いな。

1
<?=decbin(fgets(STDIN));
変換先指定対応版
1
<?$a=split(' ',fgets(STDIN));echo base_convert($a[0],10,$a[1]>0?$a[1]:2);
正攻法で。
冒頭の 変数b の値が基数で、2~10まで対応してます。

短くとか.. 勘弁してください
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<x:stylesheet version="2.0"
  xmlns:x="http://www.w3.org/1999/XSL/Transform"
  xmlns:s="http://www.w3.org/2001/XMLSchema"
  xmlns:f="http://www.w3.org/2005/xpath-functions"
  xmlns:y="uri:ja.doukaku.org:my-functions"
  >
  <x:variable name="b" as="s:integer" select="2"/>
  <x:output method="text"/>
  <x:template match="/">
    <x:for-each select="0 to 256">
      <x:value-of select="y:f(.)"/>
      <x:text>&#xA;</x:text>
    </x:for-each>
  </x:template>
  <x:function name="y:f" as="s:string">
    <x:param name="n" as="s:integer"/>
    <x:value-of select="if ($n=0) then '0' else f:string-join(f:reverse(y:g($n)),'')"/>
  </x:function>
  <x:function name="y:g" as="s:string*">
    <x:param name="n" as="s:integer"/>
    <x:if test="$n>0">
      <x:sequence select="s:string($n mod $b)"/>
      <x:sequence select="y:g($n idiv $b)"/>
    </x:if>
  </x:function>
</x:stylesheet>
短くなった。卑怯くさいけど。

#7254のコードを利用してますが、
基数だけは弄れるようにしておきました。
1
2
3
4
<stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Transform">
  <import href="http://tinyurl.com/58455r"/>
  <variable name="b" select="2"/>
</stylesheet>
Math::BaseCalcモジュールを使用して。
コマンドライン引数に基数(2,8,16等)、数値の順で指定します。
 % perl xxx.pl 2 256
 100000000
 % perl xxx.pl 8 256
 400
 % perl xxx.pl 16 256
 100
基数が2,8,10,16だったら匿名の方のようにそれぞれ%b %o %d %xを指定すればsimpleでいいですね。
1
2
3
use Math::BaseCalc;
$c=new Math::BaseCalc(digits=>[0..($ARGV[0]-1)]);
print$c->to_base($ARGV[1]);

Java6付属のRhinoでワンライナー。 コマンドライン引数から整数を受け取る。

1
jrunscript -e "print((arguments[0]*1).toString(2))" 123

標準入力から一行読み込んで変換。

1
2
3
4
5
import std.stdio, std.conv, std.string;

void main() {
    writefln("%b",to!(int)(strip(readln)));
}
クラス使って
やりなおし
してみました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/usr/bin/env gosh

(define-class <num> ()
   ((n :init-value 0 :init-keyword :n :accessor n-num)
    (b :init-value 2 :init-keyword :b :accessor b-num)))

(define-method write-object ((n <num>) port)
  (print (number->string (n-num n) (b-num n))))

(define (main args)
  (display "input number > ")(flush)
  (print (make <num> :n (x->number(read)))))

無駄にsedで実装してみます。標準入力。2進のみ。

かなりダサいので誰か短くしてください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/bin/sed -f
s/^/@/
:a
/@0\?$/{s///;b}
/[02468]$/s/.*@/0&/
/[13579]$/s/.*@/1&/
s/@/&#/
:b
/#1$/{
  s///
  ba
}
/#10/{s//5#/;bb}
/#11/{s//5#1/;bb}
/#12/{s//6#/;bb}
/#13/{s//6#1/;bb}
/#14/{s//7#/;bb}
/#15/{s//7#1/;bb}
/#16/{s//8#/;bb}
/#17/{s//8#1/;bb}
/#18/{s//9#/;bb}
/#19/{s//9#1/;bb}
/#[3579]/{
  h
  s/.*#\(.\)*/\1/
  y/3579/1234/
  G
  /#.$/{s/\(.\)\n\(.*\)#./\2\1/;ba}
  s/\(.\)\n\(.*\)#./\2\1#1/
  bb
}
/#[02468]/{
  h
  s/.*#\(.\).*/\1/
  y/02468/01234/
  G
  s/\(.\)\n\(.*\)#./\2\1#/
}
/#./bb
s/#//
ba

外部コマンドを使って楽するとこんな感じ。ほとんど単なるsh。

標準入力に「10」とか食わせると2進変換、「10 8」のように空白で区切って基数を付けるとその基数で変換。

1
2
/\(.*\) \+\(.*\)/{s//echo "obase=\2;\1"|bc/e;b}
s/.*/echo "obase=2;&"|bc/e

こっちのほうが短いですね。

1
2
3
s/\(.*\) \+\(.*\)/echo "obase=\2;\1"|bc/e
t
s/.*/echo "obase=2;&"|bc/e

標準入力経由で。

1
object M{def main(a:Array[String]):Unit=print(Integer.toString(readInt,2))}

lunlumoさんのをベースに、不要な部分を削ってみました。主な違いは

  • object M { def main ... } を object M extends Application { ... } に置き換え
  • Integer.toString(readInt,2) を readInt.toBinaryStringに置き換え

です。

1
object M extends Application{print(readInt.toBinaryString)}

printfと標準入力の組み合せで。

1
printf '%b',<>
Erlangのインタプリタコマンドであるescriptで実行するとしたケースです。
その場合、コードの最初の行は無視されるので、コメント行となっています。

入力となる10進数は、標準入力から与えます。

実行例(スクリプトファイル名を t.erl とします)
$ escript  t.erl
2
10
$
1
2
%
main(_)->{V,_}=string:to_integer(io:get_line('')),io:format("~.2B~n",[V]).
オリジナリティー低いです。
genzonさんの def はずしてワンライナーにしただけかも。
1
print Integer.toBinaryString(System.in.newReader().readLine().toInteger())
なんか同じような定義があっていまいちです。。。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
toChar n = (['0'..'9']++['A'..'Z']++['a'..'z'])!!n

toStr 0 _ = "0"
toStr n b = toStr' n b
    where
        toStr' 0 _ = ""
        toStr' n b = toStr' (n `div` b) b ++ [toChar (n `mod` b)]

main = do
    putStrLn $ toStr 0 10
    putStrLn $ toStr 255 2
    putStrLn $ toStr 255 10
    putStrLn $ toStr 255 16
    putStrLn $ toStr 255 32

割り算を使わずに作ってみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
let _ =
    let rec loop input result sr =
        let i = input lsr sr in
        if i = 0 then
            result
        else begin
            let result = (string_of_int (i land 1)) ^ result in
            loop input result (sr + 1);
        end;
    in

    let input = int_of_string (Sys.argv.(1)) in
    if input = 0 then
        print_endline "0"
    else
        print_endline (loop input "" 0);
;;
モジュールを使わずに短く書くことを目指しました。84バイトです。
第一引数が基数,第二引数が変換する10進数です。
1
($b,$n)=@ARGV;while($n){unshift@a,$n%$b;$n=int$n/$b}print@a?map{(0..9,A..Z)[