Недавно решал задачи по криптографии, и возникла необходимость переводить очень большие числа из одной системы счисления в другую. С двоичной, восьмеричной, десятичной и шестнадцатеричной системой справляется и стандартный калькулятор ОС. Но он не рассчитан на числа большой длины. А мне как раз необходимо работать с числами длиной >1000 знаков.
Для этих целей решил написать небольшой консольный конвертер, позволяющий работать с числами любой длины и любой системы счисления от 2 до 36.
Требования:
• Конвертер должен работать с числами любой длины.
• Конвертер должен работать в любой системе счисления от 2 до 36.
• Конвертер должен уметь работать с файлами.
Реализация:
Писать решил на языке C++. Люблю этот язык, да и перевести исходники в другой язык из C++ не составляет особого труда.
Написал следующий класс:
class Converter{
private:
//Вектор содержит исходное число
vector<int> a;
//Исходная система счисления
int iriginal;
public:
//Конструктор, содержит 2 параметра: строка исходного числа, исходная система счисления
Converter(string str, int original){
this->iriginal = original;
//Заносит числа исходного числа в вектор
for ( int i=0; i < str.length(); i++ ){
this->a.push_back(charToInt(str[i]));
}
}
//Переводит символ в число, вместо некорректных символов возвращает -1
int charToInt(char c){
if ( c >= '0' && c <= '9' && (c - '0') < this->iriginal ){
return c - '0';
}else{
if ( c >= 'A' && c <= 'Z' && (c - 'A') < this->iriginal ){
return c - 'A' + 10;
}else {
return -1;
}
}
}
//Переводит число в символ
char intToChar(int c){
if ( c >= 0 && c <= 9 ){
return c + '0';
}else{
return c + 'A' - 10;
}
}
//Получает следующую цифру числа в новой системе счисления
int nextNumber(int final){
int temp = 0;
for ( int i = 0; i<this->a.size(); i++){
temp = temp*this->iriginal + this->a[i];
a[i] = temp / final;
temp = temp % final;
}
return temp;
}
//Возвращает true - если массив состоит из одних нулей и false в противном случае
bool zero(){
for ( int i=0; i<this->a.size(); i++ ){
if ( a[i] != 0 ){
return false;
}
}
return true;
}
//Конвертирует исходное число в заданную систему счисления
string convertTo(int final){
vector<int> b;
int size = 0;
do {
b.push_back(this->nextNumber(final));
size++;
}while( !this->zero() );
string sTemp="";
for (int i=b.size()-1; i>=0; i--){
sTemp += intToChar(b[i]);
}
return sTemp;
}
};
Код получился достаточно простой
Далее прикрутил его в проект:
//Адрес файла, содержащего исходное число
string inputFile = argv[1];
//Исходная система счисления
int original = atol(argv[2]);
//Требуемая система счисления
int final = atol(argv[3]);
//Строка, содержащая исходное число
string origNumber;
ifstream fin(inputFile.c_str());
if ( fin.is_open() ){
fin >> origNumber;
}else{
cout << "File " << inputFile << " not open" << endl;
//Небольшой костыль - если неудалось открытьфайл, возможно вместо его ввели требуемое число
origNumber = inputFile;
}
fin.close();
Converter conv(origNumber,original);
//Если не был задан файл для вывода, то результат отобразиться на экране
if ( argc > 4 ){
//Адрес файла для записи нового числа
string outputFile = argv[4];
ofstream fout(outputFile.c_str());
if ( fout.is_open() ){
fout << conv.convertTo(final);
}else{
cout << "File " << outputFile << " not create" << endl;
cout << conv.convertTo(final) << endl;
}
}else{
cout << conv.convertTo(final) << endl;
}
Код, конечно, далек от идеала, но зато все просто и понятно.
Теперь можно протестировать.
Конвертер готов, теперь осталось его испытать. Создаю файл, содержащий число, представляющее из себя тысячу девяток.
Запускаю в консоли:
Конвертер удачно создает файл output.txt, содержащий число, длиной 3322 символа.
Теперь выведу его на экран, для этого достаточно не задавать файл для вывода.
Так же можно задавать исходное число прямо в консоли
Вывод:
Если нужно конвертировать что-то очень большое, то данный конвертер отлично для этого подойдет. Отсутствие интерфейса позволяет без изменения запускать написанный код на любой платформе. А консоль забывать нельзя, будь то windows или Linux…
Скачать проект(VS 2008) можно здесь.
Автор: flash2048
Спасибо!