Так как все эти задачки уже давно решены, вам нет необходимости изобретать велосипед, а достаточно просто обратится к исходному коду и найти готовый пример.
Так перевод чисел из различных систем исчисления в друг друга может быть найден в системной (POSIX) функции printf исходный код которой доступен в свободном доступе. Если вы не уверены в том где находится нужные вам исходники воспользуйтесь поиском codesearch.google.com и задайте в условиях требуемое имя фнукции (printf).
Перевод делается по простому алгоритму.
- В начале вы считываете входное значение и преобразуете его в числовой формат.
- Следующим шагом является перевод числа в требуемую систему исчисления
- Затем, перевод полученного значения в прописное представление:
- Пропись может иметь языковую ориентацию и иметь свои особенности перевода в русскую, английскую, немецкую или в еврит. Где по разному пишутся и взаимодействуют между собой числительные.
- Кроме того иметь различные переводы при сохранеии языковых конструкций.
Таким образом мы получаем несколько ключевых объектов:
- Входной поток (реализован через stl::iostream)
- Перевод числа в текстовое представление (реализован через Encoding)
- Языковые особенности (реализован через Lingvo_RU)
- Локализация (реализован через Locale_RU)
Комбинируя все возможные варианты представленных классов, и дописывая новые без труда можно получить перевод чисел в пропись для любого существующего языка.
Перевод строкового представления числа (уже строки а не машинного числа) в пропись делается простыми шагами. Сам стиль реализации подразумевает атомарность всех вычислений (стиль erlang) и отсутствие классов состояния\отсутствие сайд эффектов. Вычисления производятся через рекурсивный вызов одной и той же функции, каждый раз откусывающей начало массива, и передающая сама в себя конец не обработанных данных.
По просу говоря, функция обрабатывает только ту часть, которую может обработать в данный момент, и передает на следующий уровень остаток, который еще не обработан. Такая схема может предпологать создание распределенной сети вычислений. Позволяющий преобразовывать гигантские объемы входных чисел в текстовое представление. Так как большинство порядков чисел не коррелированы и одно строковое представление числа может быть преобразованно в текстовое представление на нескольких независмых машинах по схеме Map/Reduce. Но это отдельная тема.
В нашем же случае, расчет делается следующими рекурсивными шагами, каждый из которых отъедает начало списка:
- Определение разрядности
- Перевод найденного разряда в текст
например число 1000000 (один миллион) переводится в текст за следующее число операций:
первый шаг:
1(0000000) = разрядность миллион, значение 1
второй шаг:
000(000) = разрядность тысяча, значение отсутствует
третий шаг:
000() = разрядность единицы, значение отсутствует.
Еще один момент который я хотел бы рассмотреть подробно - это перевод разряда в текст.
Любое число попадающее в эту функции подвергается анализу в лингвистическом модуле. Он определяет размерность числительного и пол разряда. Как это работает?
Размерность числетельных влияет на то какое окончание будет у разряда. Например: одна тысяч(а), две тысяч(и), пять тысяч(). И в свою очередь, что бы совсем было не сладко, порядок будет влиять на числительное. Например: од(ин) миллион, од(а) тысяча и так далее до дрожи в коленках.
#include <string>
#include <algorithm>
#include <vector>
#include <locale>
#include <iostream>
class Error : public std::exception
{
public:
Error(const char* text) : std::exception(text)
{
}
};
class Locale
{
public:
enum Digits{ NONE, UNITS, TENS, HUNDRED, THOUSAND, MILLION, BILLION, TRILLION };
};
class Locale_RU : public Locale
{
public:
enum Sex {SEXNONE, MALE, FEMALE};
// од(ин), двадцать один миллиард().
// дв(а), три, четыре миллиард(а).
// пять, шесть, семь, восемь, девять, десять миллиард(ов).
// одн(а), двадцать одина тысяч(а).
// дв(е), три, четыри тысяч(и).
// пять, шесть, семь, восемь, девять, десять тысяч().
enum Count {COUNTNONE, ONE, TWOTHREEFOUR, FIVEMORE};
static Sex get_grender(Locale::Digits type)
{
switch(type)
{
case THOUSAND:
return FEMALE;
break;
case MILLION:
case BILLION:
case TRILLION:
return MALE;
break;
default:
return SEXNONE;
}
}
static Count to_simple(char number)
{
int index = number - '0';
switch(index)
{
case 1:
return ONE;
break;
case 2:
case 3:
case 4:
return TWOTHREEFOUR;
break;
case 5:
case 6:
case 7:
case 8:
case 9:
case 0:
return FIVEMORE;
default:
throw Error("bad to_simple");
}
}
static const char* to_simple(char number, Locale::Digits type)
{
std::vector<const char*> table;
switch(get_grender(type))
{
case FEMALE:
{
const char* t[]=
{"ноль", "одна", "две", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять"};
table.assign(&t[0], &t[sizeof(t) / sizeof(const char*)]);
}
break;
case SEXNONE:
case MALE:
{
const char* t[]=
{"ноль", "один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять"};
table.assign(&t[0], &t[sizeof(t) / sizeof(const char*)]);
}
break;
}
int i = number - '0';
return table.at(i);
}
static const char* to_ten(int number)
{
int index = number - '0';
const char* table[]= {"десять", "одиннадцать", "двенадцать", "тринадцать", "четырнадцать",
"пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать"};
if(index < 0 || index >= sizeof(table))
throw Error("to_hundred limit exception");
return table[index];
}
static const char* to_ten_plus(int number)
{
int index = number - '1';
const char* table[]= {"десять", "двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят",
"семьдесят", "восемьдесят", "девяносто"};
if(index < 0 || index >= sizeof(table))
throw Error("to_hundred limit exception");
return table[index];
}
static const char* to_hundred(char number)
{
int index = number - '1';
const char* table[]= {"сто", "двести", "триста", "четыреста", "пятьсот", "шестьсот",
"семьсот", "восемьсот", "девятьсот"};
if(index < 0 || index >= sizeof(table))
throw Error("to_hundred limit exception");
return table[index];
}
static std::string get_end(Locale::Digits type, Locale_RU::Count count)
{
std::string end;
switch(get_grender(type))
{
case NONE:
break;
case FEMALE:
switch(count)
{
case ONE:
end = "а";
break;
case TWOTHREEFOUR:
end = "и";
break;
case FIVEMORE:
end = "";
break;
}
break;
case MALE:
switch(count)
{
case ONE:
end = "";
break;
case TWOTHREEFOUR:
end = "а";
break;
case FIVEMORE:
end = "ов";
break;
default:
throw Error("bad count");
}
break;
}
return end;
}
static std::string to_text(Locale::Digits type, Locale_RU::Count count)
{
std::string end;
std::string word;
end = get_end(type, count);
switch(type)
{
case UNITS:
break;
case THOUSAND:
word = "тысяч";
break;
case MILLION:
word = "миллион";
break;
case BILLION:
word = "миллиард";
break;
case TRILLION:
word = "триллион";
break;
default:
throw Error("bad type");
}
return word + end;
}
};
// Лингвистический оптимизатор. Адаптирует числовое предсталвение произношению\письму\языку.
class Lingvo
{
public:
std::string concat_word(const std::string& w1, const std::string& w2)
{
std::string str(w1);
static std::locale loc = std::locale("");
int len = str.length();
if(str.length() > 0 && w2.length() > 0)
{
if(!std::isspace(str[len - 1], loc))
str += " ";
}
str += w2;
return str;
}
};
template <class L>
class Lingvo_RU : public Lingvo
{
public:
std::string to_simple(const std::string &str, Locale::Digits type)
{
std::string ret = "";
ret = concat_word(ret, L::to_simple(str[0], type));
Locale_RU::Count count = L::to_simple(str[0]);
ret = concat_word(ret, L::to_text(type, count));
return ret;
}
std::string to_ten(const std::string &str, Locale::Digits type, int cut_len)
{
int len = str.length();
std::string head = "";
std::string tail = "";
std::string ret = "";
head = str.substr(0, cut_len);
tail = str.substr(0 + cut_len, len - cut_len);
ret = concat_word(ret, to_ten(tail, type));
return ret;
}
std::string to_ten(const std::string &str, Locale::Digits type)
{
int len = str.length();
std::string ret = "";
switch(len)
{
//10-99
case 2:
switch(str[0])
{
case '0':
ret = concat_word(ret, to_ten(str, type, 1));
break;
case '1':
ret = concat_word(ret, L::to_ten(str[1]));
ret = concat_word(ret, L::to_text(type, Locale_RU::FIVEMORE));
break;
default:
ret = concat_word(ret, L::to_ten_plus(str[0]));
ret = concat_word(ret, to_ten(str, type, 1));
break;
}
break;
// 0-9
case 1:
switch(str[0])
{
case '0':
ret = concat_word(ret, to_ten(str, type, 1));
break;
default:
ret = concat_word(ret, to_simple(str, type));
break;
}
break;
case 0:
ret = concat_word(ret, L::to_text(type, Locale_RU::FIVEMORE));
break;
default:
throw Error("wrong to_ten len");
}
return ret;
}
std::string to_hundred(const std::string &str, Locale::Digits type, int cut_len)
{
int len = str.length();
std::string head = "";
std::string tail = "";
std::string ret = "";
head = str.substr(0, cut_len);
tail = str.substr(0 + cut_len, len - cut_len);
ret = concat_word(ret, to_hundred(tail, type));
return ret;
}
std::string to_hundred(const std::string &str, Locale::Digits type)
{
int len = str.length();
std::string ret = "";
switch(len)
{
//000-900
case 3:
if(str == "000")
return ret;
switch(str[0])
{
case '0':
ret = concat_word(ret, to_hundred(str, type, 1));
break;
default:
ret = concat_word(ret, L::to_hundred(str[0]));
ret = concat_word(ret, to_hundred(str, type, 1));
break;
}
break;
//10-99
case 2:
switch(str[0])
{
case '0':
ret = concat_word(ret, to_hundred(str, type, 1));
break;
default:
ret = concat_word(ret, to_ten(str, type));
break;
}
break;
// 0-9
case 1:
switch(str[0])
{
case '0':
ret = concat_word(ret, to_hundred(str, type, 1));
break;
default:
ret = concat_word(ret, to_simple(str, type));
break;
}
break;
case 0:
ret = concat_word(ret, L::to_text(type, Locale_RU::FIVEMORE));
break;
default:
throw Error("wrong hundred len");
}
return ret;
}
// cut and parse
std::string to_digits(const std::string &str, Locale::Digits type, int cut_len)
{
int len = str.length();
std::string head = "";
std::string tail = "";
std::string ret = "";
head = str.substr(0, cut_len);
tail = str.substr(0 + cut_len, len - cut_len);
ret = concat_word(ret, to_hundred(head, type));
ret = concat_word(ret, to_string(tail));
return ret;
}
std::string to_digits(const std::string &str, Locale::Digits type)
{
int len = str.length();
std::string ret = "";
switch(len)
{
// триллион 1 000 000 000 000 - 100 000 000 000 000
case 15:
case 14:
case 13:
ret = concat_word(ret, to_digits(str, Locale::TRILLION, len - 12));
break;
// миллиард 1 000 000 000 - 100 000 000 000
case 12:
case 11:
case 10:
ret = concat_word(ret, to_digits(str, Locale::BILLION, len - 9));
break;
// миллион 1 000 000 - 100 000 000
case 9:
case 8:
case 7:
ret = concat_word(ret, to_digits(str, Locale::MILLION, len - 6));
break;
// тысяча 1 000 - 100 000
case 6:
case 5:
case 4:
ret = concat_word(ret, to_digits(str, Locale::THOUSAND, len - 3));
break;
// сотня 100
case 3:
ret = concat_word(ret, to_digits(str, Locale::UNITS, len - 0));
break;
// 10
case 2:
ret = concat_word(ret, to_ten(str, type));
break;
// 0-9
case 1:
ret = concat_word(ret, to_simple(str, type));
break;
case 0:
break;
default:
throw Error("big value");
}
return ret;
}
std::string to_string(const std::string &str)
{
return to_digits(str, Locale::UNITS);
}
};
class Encoding
{
public:
const char to_char(int i)
{
static const char c[] = {"0123456789ABCDEF"};
if(i >= sizeof(c))
throw Error("to_char limit exception");
return c[i];
}
};
class Encoding_DEC : public Encoding
{
public:
template <class T>
std::string convert(T number)
{
std::string str = "";
while (number >= 10)
{
str += to_char(number % 10);
number /= 10;
}
str += to_char((int)number);
std::reverse(str.begin(), str.end());
return str;
}
};
class Encoding_OCT : public Encoding
{
public:
template <class T>
std::string convert(T number)
{
std::string str = "";
char last = 0;
do {
last = to_char(number & 7);
str += last;
number >>= 3;
} while (number);
if ( last != '0')
number += '0';
std::reverse(str.begin(), str.end());
return str;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
long long i = 111111111111111;
setlocale(LC_ALL, "Russian");
while(true)
{
std::cout<<"Вводим: "<<std::endl;
std::cin>>i;
std::cout<<"Выводим: "<<std::endl;
{
Encoding_DEC enc;
std::string s = enc.convert(i);
Lingvo_RU<Locale_RU> locale;
std::string verb = locale.to_string(s);
std::cout<<verb<<" в десятичной системе;"<<std::endl;
}
{
Encoding_OCT enc;
std::string s = enc.convert(i);
Lingvo_RU<Locale_RU> locale;
std::string verb = locale.to_string(s);
std::cout<<verb<<" в восьмеричной системе."<<std::endl;
}
std::cout<<std::endl;
}
return 0;
}


2 коммент.: