マルチスケールシミュレーション特論： roman numerals 



# はじめに

今回は課題としてアラビア数字からローマ数字に変換するという課題が出たので、その課題を解いてみる事にする


# 解答


## プログラム

-   正直全く良い方法分からない、、、、、

```ruby
num = ARGV[0]

def divide_num(num)
  ans_list,count = [],0
  while num > 0
    tmp = num % 10
    ans_list.push(tmp * (10 ** count))
    num = num / 10
    count = count + 1
  end
  return ans_list.reverse
end

ans_list,count = divide_num(num.to_i),0

def num_to_roman_hundred(num)
  if num == 900
    print "CM"
  elsif num <= 800 && num >= 500
    num = num - 500
    if num != 0
      print "D" + "C" * (num / 100)
    else
      print "D"
    end

  elsif num == 400
    print "CD"

  elsif num <= 300 && num >= 100
    num = num - 100
    if num != 0
      print "C" + "C" * (num / 100)
    else
      print "C"
    end
  end
end

def num_to_roman_ten(num)
  if num == 90
    print "XC"
  elsif num <= 80 && num >= 50
    num = num - 50
    if num != 0
      print "L" + "X" * (num / 10)
    else
      print "L"
    end

  elsif num == 40
    print "XL"

  elsif num <= 30 && num >= 10
    num = num - 10
    if num != 0
      print "X" + "X" * (num / 10)
    else
      print "X"
    end
  end
end

def num_to_roman(num)
  roman_first = ['I','II','III','IV','V','VI','VII','VIII','IX','X']

  if num >= 1000
    tmp = num / 1000
    x = "M" * tmp
    print x

  elsif num <= 900 && num >= 100
    num_to_roman_hundred(num)
  elsif num <= 90 && num >= 10
    num_to_roman_ten(num)
  elsif num <= 10 && num >= 1 
    print roman_first[num-1]

  end
end

for i in ans_list do
  num_to_roman(i)
end

print "\n"

```

自分で書いてて思います。頭悪い実装です(笑)

(深夜にやっていて頭回ってないという言い訳をしときます(笑))


## 個別の関数毎の説明

-   divide\_num 関数の中で受けとった数字を分解

-   num\_to\_roman\_hundred, num\_to\_roman\_ten はそれぞれの桁数に合わせてローマ数字に変換を行う

-   num\_to\_roman で全ての数字をローマ数字に変換

-   **追記**
    -   コードの改良を行った &#x2013; 11/21
    -   改良版を下の方に載せときます


# 答え合わせ

では作成したプログラムが正しいかどうかの答え合わせをしましょう!!

-   以下のようなプログラム(a.sh)を作成します
    
    ```bash
    for i in $(seq 1 3999);do
      ruby a.rb $i # a.rb はソースコードの名前なので何でもいいです
    done
    ```

-   bash a.sh > tmp.txt

-   エクセルから 3999 までのローマ数字を作成(1 分以内で可能)し、tmp2.txt として保存

-   diff tmp.txt tmp2.txt

何も出力されなければ成功!!

逆に出力されたら失敗してます。。。


# **追記(コード改良版)**

-   num\_to\_roman\_hundred と num\_to\_roman\_ten の関数を統合してnum\_to\_roman\_each 関数に変更した(new\_roman\_numeral.rb)

これで少しはコード少くなったかな？

(元のアルゴリズムが良くないからそんなに短くなってないけど、、、、)

```ruby
num = ARGV[0]

def divide_num(num)
  ans_list,count = [],0
  while num > 0
    tmp = num % 10
    ans_list.push(tmp * (10 ** count))
    num = num / 10
    count = count + 1
  end
  return ans_list.reverse
end

ans_list,count = divide_num(num.to_i),0


def num_to_roman_each(num, f_str, s_str, t_str, fo_str)
  f_num = num.to_s[0].to_i
  if f_num == 9
    print f_str

  elsif f_num <= 8 && f_num >= 5
    if (f_num - 5) != 0
      print s_str + t_str * (f_num - 5)      
    else
      print s_str
    end

  elsif f_num == 4
    print fo_str

  elsif f_num <= 3 && f_num >= 1
    if (f_num - 1) != 0
      print t_str + t_str * (f_num - 1)
    else
      print t_str
    end

  end
end

def num_to_roman(num)
  roman_first = ['I','II','III','IV','V','VI','VII','VIII','IX','X']

  if num >= 1000
    tmp = num / 1000
    x = "M" * tmp
    print x

  elsif num <= 900 && num >= 100
    num_to_roman_each(num, "CM", "D", "C", "CD")

  elsif num <= 90 && num > 10
    num_to_roman_each(num, "XC", "L", "X", "XL")

  elsif num <= 10 && num >= 1 
    print roman_first[num-1]

  end
end

for i in ans_list do
  num_to_roman(i)
end

print "\n"
```


# GitHub

以下の URL に全てのプログラムと txt file を置いておきます。

-   <https://github.com/taiseiyo/roman_numerals>



------
 - **source** ~/Downloads/git/grad_members_20f/members/taiseiyo/memos/roman.org