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 件のコメント:
コメントを投稿