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