1.15.2012

Roman numerals conversion in C++

C++: ローマ数字の変換処理

ためしに実装してみた。
整数と文字列2種類のコンストラクタを持ち、入力チェックは行なっていない。
整数であれば、1以上3,999,999以下の範囲、文字列は正しいローマ数字である場合にのみ正しく動作する。

・RomanNumeral クラス

#include <string>
#include <cmath>

//------------------------------------------------------------------------------
// Roman numerals conversion
//------------------------------------------------------------------------------
std::string const kRomanNumeralTable = "IVXLCDMvxlcdm";
class RomanNumeral {
 public:
  RomanNumeral(int decimal) : _decimal(decimal) {
    std::string roman;
    int i = 0;
    while (decimal) {
      std::string s;
      int d = decimal % 10;
      while (d) {
        if ((d - 1) & 4) {
          s.push_back(kRomanNumeralTable[i * 2 + 1]);
          d -= 5;
          continue;
        }
        if (d == 10) {
          s.push_back(kRomanNumeralTable[i * 2 + 2]);
          break;
        }
        s.push_back(kRomanNumeralTable[i * 2]);
        d -= d % 5 == 4 ? -1 : 1;
      }
      roman = s + roman;
      ++i;
      decimal /= 10;
    }
    _roman = roman;
  }
  RomanNumeral(std::string roman) : _roman(roman){
    int decimal = 0;
    int prev = 1000000000;

    for (std::string::const_iterator i = roman.begin(); i != roman.end(); ++i) {
      int pos = kRomanNumeralTable.find(*i);
      int weight = static_cast<int>(pow(10.0, (pos + 1) / 2)) / (pos % 2 + 1);
      if (prev < weight) decimal -= prev * 2;
      decimal += prev = weight;
    }
    _decimal = decimal;
  }

  int decimal() const { return _decimal; }
  std::string roman() const { return _roman; }

 private:
  int _decimal;
  std::string _roman;
};

・呼び出し側コード

#include <iostream>
#include <cassert>

int main() {
  for (int i = 1; i <= 3999999; ++i) {
    std::string s = RomanNumeral(i).roman();
    int x = RomanNumeral(s).decimal();
    assert(i == x);
  }

  for (int i = 1; i <= 20; ++i) {
    std::string s = RomanNumeral(i).roman();
    int x = RomanNumeral(s).decimal();
    std::cout << x << ": " << s << std::endl;
  }

  return 0;
}

・出力結果

1: I
2: II
3: III
4: IV
5: V
6: VI
7: VII
8: VIII
9: IX
10: X
11: XI
12: XII
13: XIII
14: XIV
15: XV
16: XVI
17: XVII
18: XVIII
19: XIX
20: XX

0 件のコメント:

コメントを投稿