Переводы между системами счисления



В этой главе рассмотрим переводы между разными системами счисления. Помимо привычной десятичной существуют и другие- например, пятеричная. Там всего 5 цифр: 0, 1, 2, 3, 4. А далее 10, 11 и т.д.

Задача в том, чтобы вот я ввожу например обычное десятичное число и надо перевести его в двоичное. Вход: 9, выход: 1001.

В идеале написать не просто перевод в именно двоичную систему, но вообще в любую до десяти. Давайте сначала напишем перевод именно в двоичную.

Как вообще происходит перевод? Мы будем использовать число как массив цифр- это расширяет спектр возможностей и упрощает алгоритмы. Функции для ввода, вывода и т.п. мы уже написали. Хотя смысла особо нет, т.к. нам всё равно нужно абсолютное значение- нам нужно брать логарифм.

Сначала нужно понять, сколько цифр будет в двоичном числе:

0-1 -> 1

2-3 -> 2

4-7 -> 3

В итоге мы берём двоичный логарифм, убираем дробную часть и прибавляем 1.

Хранить двоичное число как массив цифр будем хранить как приняли- в первом элементе кол-во цифр, а далее сами цифры. На вход в качестве десятичного будем подавать обычный int.

int log2 (int x) { return int(log(x)/log(2));} // целая часть двоичного логарифма

int *DecToBin (int x) {

           int size= log2(x) + 1; // кол-во цифр двоичного числа

           int *res= new int [size+1]; // само двоичное число- массив для его хранения

           res[0]= size; // в 1-м элементе храним размер

           // далее реализовано то что на картинке выше

           for(int i= log2(x); i>=0; i--) {

                           if(x - pow(2,i) <0) {

                                           res[size-i]= 0;

                                           continue;

                           }

                           else {

                                           res[size-i]= 1;

                                           x-= pow(2,i);

                           }

           }

           return res;

}

Тестировать можно так:

int x; cin>>x;

Kosh_Print(DecToBin(x));

Есть один недостаток- с нулём не работает, т.к. логарифм из него не берётся. Поэтому пропишем это условие отдельно, дополним функцию:

...

Теперь попробуем переводить в другую систему счисления- сделать более универсально. Посмотрим на примере троичной как это происходит:

Теперь можно написать алгоритм- не только для троичной, но и для любой системы счисления с кол-вом цифр от 2 до 9.

int Log (int x, int n) { return int(log(x)/log(n)); }

// osn= {2,3,4,5,6,7,8,9}

int *Dec_To_Min (int x, int osn= 3) {

           if(!x) {

                           int *res= new int [2];

                           res[0]= 1; res[1]= 0;

                           return res;

           }

           else {

                           int size= Log(x,osn) + 1;

                           int *res= new int [size+1];

                           res[0]= size;

                           for(int i= Log(x,osn); i>=0; i--) {

                                           res[size-i]= x/pow(osn,i);

                                           x%= (int)pow(osn,i);

                           }

                           return res;

           }

}

Теперь решим обратную задачу: перевод из системы с основанием 2-9 в десятичную обратно. Тут всё даже проще: чисто делается сумма будто вычисляется значение полинома.

Теперь сама функция перевода:

int Min_To_Dec (int x[], int osn= 3) {

           int size= x[0];

           int res= 0;

           for(int i= size-1; i>=0; i--) res+= x[size-i]*pow(osn,i);

           return res;

}

Можно хранить число в более расширенном виде: в 1-м элементе хранить например количество цифр, а во 2-м элементе уже основание системы счисления. Это расширит возможности- т.е. функции сами автоматически будут определять, в какой системе счисления число- но при этом алгоритмы станут сложнее.

Сначала лучше запишем функцию, которая переводит например из троичной системы в пятеричную. Это уже легко будет сделать, т.к. мы будем использовать десятичную систему как буферную, промежуточную. Т.е. мы троичное число переводим сначала в десятичное, а потом это десятичное уже в пятеричное.

int *Perevod_System_Min (int x[], int osn_from, int osn_to) {

           return Dec_To_Min(Min_To_Dec(x,osn_from),osn_to);

}

...

Мы рассмотрели только системы счисления, которые меньше 10- т.е. они содержат привычные нам цифры. Поэтому в названиях функций выше и была приписка Min. Но есть системы с количеством чисел больше 10, например 16-ричная. Тут проблема в том, что в качестве цифр дальше уже используются буквы: A, B, C, D, E, F для 16-ричной например. Поэтому число с основанием системы счисления больше 10 уже придётся хранить в массиве символов, при этом написать переводные функции из этих символов в цифры.

Хотя есть и другой выход- в памяти компьютера эти цифры будут храниться как обычные числа типа 10, 11, 12 и т.д. Тогда можно переводные функции даже не менять. А при выводе на консоль мы будем переводить эти цифры в буквы. Ну и при вводе буквы в цифры соответственно. Т.е. изменить придётся только функции ввода и вывода.

В таблице ASCII заглавные английские буквы идут подряд- это можно использовать. Так как цифры 10, 11 и т.д. тоже идут соответственно им подряд.

Эта команда выведет таблицу:

for(int i=0; i<=255; i++) cout << i << " --> " << (char)i << endl;

65 --> A

66 --> B

67 --> C

68 --> D

69 --> E

70 --> F

48 --> 0

49 --> 1

50 --> 2

Этого отрывка нам будет достаточно для понимания как запрограммировать перевод символьной цифры в числовую.

char IntDigit_To_Char (int x) {

           if( (x>=0)&&(x<=9) ) return (char)(48+x);

           if(x>=10) return (char)(55+x);

}

void Kosh_Print_Max (int a[]) {

           int r= a[0];

           for (int i=1; i<=r; i++) cout << IntDigit_To_Char(a[i]);

}

Тестирование:

int x; cin>>x; int *t= Dec_To_Min(x,16);

Kosh_Print_Max(t);

Выводим 16-ричное число.

...

Теперь алгоритм ввода.

int *Kosh_Input_Max() {

           string s; cin>>s;

           int size= StringSize(s);

           int *number= new int [size+1];

           number[0]= size;

           for(int i=1; i<=size; i++) number[i]= CharToInt(s[i-1]);

           return number;

}

По сути он абсолютно такой же, вообще ничего не поменялось. Функция перевода из символа в цифру была модифицирована и всё:

int CharToInt (char c) {

           if (((int)c>=48)&&((int)c<=57)) return (int)c - 48;

           if ((int)c>=65) return (int)c - 55;

}

Пример тестирования на 14-ричной системе счисления:

int *t= Kosh_Input_Max();

int x= Min_To_Dec(t,14);

cout << x << endl;

Kosh_Print_Max(t);

...

Что касается задачи перевода из 16-ричную в троичную например- эта задача уже решена, применимы всё те же функции. Просто единственное для таких систем типа 16-ричных мы модифицировали функции ввода и вывода. Можно теперь все эти функции переименовать и получим чёткую систему, на которой тут и закончим:

int CharToInt (char c) {

           if (((int)c>=48)&&((int)c<=57)) return (int)c - 48;

           if ((int)c>=65) return (int)c - 55;

}

char IntDigit_To_Char (int x) {

           if( (x>=0)&&(x<=9) ) return (char)(48+x);

           if(x>=10) return (char)(55+x);

}

int StringSize (string s) {

           char c= s[0]; int i=0; int stringsize=0;

           while ((int)c != 0) { i++; c=s[i]; stringsize++; }

           return stringsize;

}

void Kosh_Print (int a[]) {

           int r= a[0];

           for (int i=1; i<=r; i++) cout << IntDigit_To_Char(a[i]);

}

int *Kosh_Input() {

           string s; cin>>s;

           int size= StringSize(s);

           int *number= new int [size+1];

           number[0]= size;

           for(int i=1; i<=size; i++) number[i]= CharToInt(s[i-1]);

           return number;

}

////////////////////////////////////

int Log (int x, int n) { return int(log(x)/log(n)); }

int *Dec_To_Another (int x, int osn= 3) {

           if(!x) {

                           int *res= new int [2];

                           res[0]= 1;

                           res[1]= 0;

                           return res;

           }

           else {

                           int size= Log(x,osn) + 1;

                           int *res= new int [size+1];

                           res[0]= size;

                           for(int i= Log(x,osn); i>=0; i--) {

                                           res[size-i]= x/pow(osn,i);

                                           x%= (int)pow(osn,i);

                           }

                           return res;

           }

}

int Another_To_Dec (int x[], int osn= 3) {

           int size= x[0];

           int res= 0;

           for(int i= size-1; i>=0; i--) res+= x[size-i]*pow(osn,i);

           return res;

}

int *Perevod_System (int x[], int osn_from, int osn_to) {

           return Dec_To_Another(Another_To_Dec(x,osn_from),osn_to);

}

 


Дата добавления: 2018-09-22; просмотров: 234; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!