Last active
December 28, 2015 14:29
-
-
Save w495/7514989 to your computer and use it in GitHub Desktop.
Перевод чисел в систему исчисления с основанием от 2 до 95 (участвуют все печатные символы таблицы `ASCII`). Для случае основания равного `64`, формула преобразования не совпадает со стандартным `base64`. Ниже самого кодировщика приведены программы для декодирования на языках Python и Erlang. Подробное описание в комментариях.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** **************************************************************************** | |
* | |
* @mainpage Перевод всех байтов входного потока в заданную систему счисления. | |
* | |
* @section ОПИСАНИЕ | |
* Программа переводит все байты входного потока (stdin) в заданную | |
* систему заданную счисления и печатает результат в выходной поток. | |
* При необходимости добавляет ведущие нули, для выравнивания числа | |
* до одинаковой ширины. | |
* @note Важно понимать, что байты входного потока, | |
* это просто числа в системе счисления с основанием 256. | |
* Основание системы счисления результата задается как первый аргумент | |
* командной строки при вызове программы: | |
* >$ ./basen 2 | |
* Основание системы счисления выбирается от 2 до 95. | |
* При использовании основания 95, в качестве цифр системы счисления | |
* используются все печатные символы таблицы ASCII. | |
* | |
* Пример работы программы: | |
* >$ echo 'Hello' | ./basen 2 | |
* 010010000110010101101100011011000110111100001010 | |
* >$ echo 'Hello' | ./basen 4 | |
* 102012111230123012330022 | |
* >$ echo 'Hello' | ./basen 8 | |
* 110145154154157012 | |
* >$ echo 'Hello' | ./basen 16 | |
* 48656C6C6F0A | |
* >$ echo 'Hello' | ./basen 95 | |
* 0*161D1D1G0A | |
* >$ echo 'Мама мыла раму' | ./basen 64 | |
* 3G2S3G2m3G2y3G2m0W3G2y3H2B3G2x3G2m0W3H203G2m3G2y3H230A | |
* >$ echo 'Мама мыла раму' | ./basen 95 | |
* 2I1z2I1=2I1}2I1=0W2I1}2J1i2I1|2I1=0W2J1X2I1=2I1}2J1a0A | |
* | |
* В качестве дополнительной опции можно задать разделитель между | |
* представлениями байт выходного потока. Например: | |
* >$ echo 'Hello' | ./basen 10 ' ' | |
* 072 101 108 108 111 010 | |
* >$ echo 'Hello' | ./basen 16 ' :) ' | |
* 48 :) 65 :) 6C :) 6C :) 6F :) 0A | |
* >$ echo 'Hello' | ./basen 2 $'\n' | |
* 01001000 | |
* 01100101 | |
* 01101100 | |
* 01101100 | |
* 01101111 | |
* 00001010 | |
* | |
* @subsection АЛГОРИТМ | |
* Для перевода в заданную систему исчисления используется | |
* рекурсивный алгоритм. На каждом шаге рекурсии вычисляется | |
* остаток деления байта входного потока на основание | |
* заданной систему счисления. | |
* Так определяется цифра в новой системе счисления. | |
* При обратном ходе рекурсии, происходит вывод цифры на экран. | |
* Благодаря тому, что вывод происходит именно на обратном ходе | |
* рекурсии, порядок цифр в выходном числе получается прямым. | |
* | |
* @section ЛИЦЕНЗИЯ (BSD) | |
* © 2013 Илья w-495 Никитин, кафедра 806, МАИ. | |
* Разрешается повторное распространение и использование как | |
* в виде исходного кода, так и в двоичной форме, | |
* с изменениями или без, при соблюдении следующих условий: | |
* * при повторном распространении исходного кода должно оставаться | |
* указанное выше уведомление об авторском праве, | |
* этот список условий и последующий отказ от гарантий; | |
* * при повторном распространении двоичного кода должна | |
* сохраняться указанная выше информация об авторском праве, | |
* этот список условий и последующий отказ от гарантий | |
* в документации и/или в других материалах, | |
* поставляемых при распространении; | |
* * ни название организации, ни имена ее сотрудников | |
* не могут быть использованы в качестве поддержки | |
* или продвижения продуктов, основанных на этом ПО | |
* без предварительного письменного разрешения. | |
* Эта программа предоставлена владельцами авторских прав и/или | |
* другими сторонами «как она есть» без какого-либо вида гарантий, | |
* выраженных явно или подразумеваемых, включая, но не ограничиваясь ими, | |
* подразумеваемые гарантии коммерческой ценности и пригодности | |
* для конкретной цели. Ни в коем случае ни один владелец авторских | |
* прав и ни одно другое лицо, которое может изменять и/или повторно | |
* распространять программу, как было сказано выше, | |
* не несёт ответственности, включая любые общие, | |
* случайные, специальные или последовавшие убытки, | |
* вследствие использования или невозможности использования программы | |
* (включая, но не ограничиваясь потерей данных, или данными, | |
* ставшими неправильными, или потерями принесенными из-за вас | |
* или третьих лиц, или отказом программы работать совместно | |
* с другими программами), даже если такой владелец | |
* или другое лицо были извещены о возможности таких убытков. | |
* | |
* @file basen.c | |
* Основной файл программы. | |
* | |
* @package basen | |
* Основной модуль программы, перевода байтов входного потока | |
* в заданную систему счисления. Основание системы счисления задается | |
* как первый аргумент командной строки при вызове программы. | |
* На вход подается произвольная последовательность байт. | |
* На выходе --- входные байты в указанной системе исчисления. | |
* | |
* @author Илья w-495 Никитин <[email protected]> | |
* @date 2013.11.18 01:50:44 | |
* @version 1.1 | |
* | |
** ***************************************************************************/ | |
#include<stdio.h> | |
#include<stdlib.h> | |
/** | |
* @typedef bool_t --- синоним для перечисления {true, false}. | |
* Просто удобно завести отдельный тип, для дальнейших вычислений. | |
**/ | |
typedef enum{FALSE = 0, TRUE = 1} bool_t; | |
/** | |
* @typedef number_t --- синоним для `int`. | |
* Просто удобно завести отдельный тип, для дальнейших вычислений. | |
**/ | |
typedef int number_t; | |
/** | |
* @typedef byte_t --- синоним для `unsigned char`. | |
* Мы используем именно `unsigned char`. | |
* Ибо именно он является абстракцией байта в языке Си. | |
* Достаточно подробно рассказано тут: | |
* habrahabr.ru/post/156593/ | |
* | |
**/ | |
typedef unsigned char byte_t; | |
/** | |
* @fn Выводит на печать число `input` в системе с основанием `base`. | |
**/ | |
number_t print_base(number_t base, number_t input, number_t width); | |
/** | |
* @fn Вычисляет целочисленный логарифм от val по основанию base. | |
**/ | |
number_t mylog(number_t base, number_t val); | |
/** | |
* @fn Вычисляет целочисленный логарифм от val по основанию 2. | |
**/ | |
number_t mylog2(number_t val); | |
/** | |
* @fn Возвращает значение (число) основания системы для преобразования. | |
* В нашем случае это первый аргумент программы. | |
**/ | |
number_t get_base(int argc, char* argv[]); | |
/** | |
* @fn Возвращает значение разделителя (это строка) для чисел в новой системе. | |
* @note Для того, чтобы в качестве разделителя использовать непечатные | |
* символы, типа '\t', '\n', и пр, нужно аргумент командной строки | |
* заключить в $'<символ>'. Например `./basen 2 $'\n' ` | |
**/ | |
const char* get_sep(int argc, char* argv[]); | |
int main(int argc, char* argv[]){ | |
/* | |
* Узнаем основание. | |
*/ | |
number_t base = get_base(argc, argv); | |
/* | |
* Узнаем разделитель (если он есть). | |
*/ | |
const char* sep = get_sep(argc, argv); | |
/* | |
* Вычислим ширину самого широкого числа, для заполнения нулями. | |
* Это логарифм по основанию системы исчисления от числа 255 | |
* с добавлением единицы. | |
*/ | |
number_t numberwidth = mylog(base, 255)+1; | |
/* | |
* Побайтно считываем файл, | |
* до тех пор пока не встретим признак конца файла. | |
* Обратите внимание на, конструкцию `(byte_t)EOF`. | |
* Это приведение типов. | |
* Т.к. `typedef unsigned char byte_t`, a EOF = -1. | |
* То наше условие без приведения типов никогда не выполнится, | |
* ибо `chr` всегда больше `0`. | |
*/ | |
byte_t chr = 0; | |
bool_t isfirst = TRUE; | |
while((chr = getchar()) != (byte_t)EOF){ | |
/* | |
* Простые манипуляции для вывода разделителя, если это требуется. | |
*/ | |
if((sep) && (FALSE == isfirst)){ | |
printf("%s", sep); | |
} | |
if (isfirst) | |
isfirst = FALSE; | |
/* | |
* Аналогичное приведение мы используем и при вызове функции. | |
* Правда тут на самом деле можно просто поменять типы у функции. | |
*/ | |
print_base(base, (number_t)chr, numberwidth); | |
} | |
printf("\n"); | |
return 0; | |
} | |
/** | |
* @fn Возвращает значение (число) основания системы для преобразования. | |
* В нашем случае это первый аргумент программы. | |
* Если аргументов недостаточно прерываем программу. | |
**/ | |
number_t get_base (int argc, char* argv[]) { | |
int res = 2; | |
if(argc < 2){ | |
fprintf(stderr, "Error: wrong usage: " | |
"at least one argument required --- " | |
"the base of number system. \n"); | |
exit(1); | |
} | |
res = abs(atoi(argv[1])); | |
/* | |
* Защита от дурака. | |
*/ | |
if ((2 > res) || (res > 95)){ | |
fprintf(stderr, "Error: wrong usage: " | |
"the base of number system " | |
"should be from 2 to 95. \n"); | |
exit(1); | |
} | |
return res; | |
} | |
/** | |
* @fn Возвращает значение разделителя (это строка) для чисел в новой системе. | |
* Если аргумент не указан, возвращает NULL. | |
**/ | |
const char* get_sep(int argc, char* argv[]) { | |
if(argc < 3){ | |
return (char *)NULL; | |
} | |
return argv[2]; | |
} | |
/** | |
* @fn Вычисляет целочисленный логарифм от `val` по основанию `base`. | |
* Тут используется формула $ log_b(a) = log_c(a) / log_c(b) $. | |
* Это не самая эффективная реализация, логарифма. | |
* Попробуйте сделать лучше, и сравнить. | |
**/ | |
number_t mylog (number_t base, number_t val) { | |
return mylog2 (val) / mylog2 (base); | |
} | |
/** | |
* @fn Вычисляет целочисленный логарифм от `val` по основанию `2`. | |
* Для двоичной системы логарифм это всего лишь количество | |
* правых сдвигов для нуля. | |
**/ | |
number_t mylog2 (number_t val) { | |
number_t ret = 0; | |
while (val != 0) { | |
val >>= 1; | |
ret++; | |
} | |
return ret; | |
} | |
/** | |
* @fn Выводит на печать число `input` в системе с основанием `base`. | |
* | |
* Рекурсивная функция перевода числа в систему исчисления с основанием | |
* от 2 до 95 (участвуют все печатные символы таблицы `ASCII`). | |
* | |
* Если `base < 10`, функция возвращает входное число (`input`) | |
* приведенное к системе `base`, т.е. разряды входного числа в системе `base` | |
* умножены на 10, (десятичный сдвиг). Если `base > 10`, функция возвращает | |
* входное число разряды которого, в системе `base` умножены на 100, | |
* (стоичный сдвиг). | |
* | |
* Возврат описанного значения не является основным назначением данной функции, | |
* но служит иллюстрацией как можно работать с системами основание, | |
* которых меньше 10, и больше 10. | |
* | |
* @WARNING: Обращаем внимание, что для случае основания равного `64`, | |
* формула преобразования данной функции не совпадает | |
* со стандартным `base64`. | |
* | |
* @param base основание системы счисления; | |
* @param input входное число; | |
* @param width ширина выводимого слова; | |
* Этот аргумент нужен, чтобы дополнять выходное число | |
* ведущему нулями, до нужного размера. | |
* Например `print_base(2, 2, 4)` напечатает `0010`. | |
* @returns если `base < 10`, `input` приведенное к системе `base`, | |
* иначе, входное число разряды которого, умножены на 100. | |
* | |
**/ | |
number_t print_base(number_t base, number_t input, number_t width){ | |
/* | |
* Получаем разряд числа `input` в системе счисления `base` | |
*/ | |
number_t digit = input % base; | |
/* | |
* Переменная для хранения предыдущих разрядом числа. | |
*/ | |
number_t prevdigits = 0; | |
/* | |
* Условие остановки рекурсии. | |
*/ | |
if(!input){ | |
number_t i; | |
/* | |
* Печатаем ведущие нули. | |
* Каждый предыдущий шаг рекурсии уменьшал `width` на единицу, | |
* т.к. к выходному числу добавлялось по разряду. | |
* Теперь мы выводим столько нулей, сколько необходимо, | |
* до дополнения до ширины `width`. | |
*/ | |
for(i = 0; i < width; ++i) | |
printf("0"); | |
return 0; | |
} | |
/* | |
* Рекурсивно вызываем эту же функцию, | |
* Параметр `base` не меняется, параметр `input` становится | |
* в `base` раз меньше, a параметр `width` уменьшаем на 1, | |
* если он был положительным (тут используется тренарный оператор). | |
* Как результат возвращает предыдущие разряды числа. | |
*/ | |
prevdigits = print_base(base, input / base, (width) ? (width - 1) : 0); | |
/** | |
* Вывод полученной цифры на печать. | |
* Тут возможны варианты. | |
* Например в стандарте Base64 предлагается иное соответствие | |
* входных и выходных цифр: | |
* http://bit.ly/181ON9I | |
**/ | |
/* | |
* Если мы получили значение разряда менее 10, | |
* то выводим его как десятичное число. | |
*/ | |
if(digit < 10) | |
printf("%d", digit); | |
/* | |
* Далее используем большие латинские буквы от `A` до `Z`. | |
*/ | |
if((10 <= digit) && (digit < 36)) | |
printf("%c", digit + 'A' - 10); | |
/* | |
* Далее используем малые латинские буквы от `a` до `z`. | |
*/ | |
if((36 <= digit) && (digit < 62)) | |
printf("%c", digit + 'a' - 36); | |
/* | |
* Далее используем символы ASCII от `32` до `47`, это: | |
* ` ` (пробел), `!`, `"`, `#`, `$`, `%`, `&`, `'`, | |
* `(`, `)`, `*`, `+`, `,`, `—`, `.`, `/` | |
*/ | |
if((62 <= digit) && (digit < 78)) | |
printf("%c", digit + ' ' - 62); | |
/* | |
* Далее используем символы ASCII от `58` до `64`, это: | |
* `:`, `;`, `<`, `=`, `>`, `?`, `@` | |
*/ | |
if((78 <= digit) && (digit < 85)) | |
printf("%c", digit + ':' - 78); | |
/* | |
* Далее используем символы ASCII от `91` до `96`, это: | |
* `[`, `\`, `]`, `^`, `_`, ``` | |
*/ | |
if((85 <= digit) && (digit < 91)) | |
printf("%c", digit + '[' - 85); | |
/* | |
* Далее используем символы ASCII от `123` до `126`, это: | |
* `{`, `|`, `}`, `~` | |
*/ | |
if((91 <= digit) && (digit < 95)) | |
printf("%c", digit + '{' - 91); | |
if(base < 10) | |
return prevdigits * 10 + digit; | |
/* | |
* Каждый разряд сдвинут на 100, (стоичный сдвиг). | |
* Примеры: | |
* 15 = 0x0f -> 15 | |
* 16 = 0x10 -> 100 | |
* 33 = 0x21 -> 201 | |
* 200 = 0xc8 -> 1208 | |
* 255 = 0xff -> 1515 | |
*/ | |
return prevdigits * 100 + digit; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf8 -*- | |
## | |
## Простая программа перевода двоичных строк входного потока, | |
## в байты выходного потока. | |
## На вход подаются строки, например | |
## 01001000 | |
## 01100101 | |
## 01101100 | |
## 01101100 | |
## 01101111 | |
## 00001010 | |
## В результате работы программы они будут переведены в строку `Hello` | |
## | |
import sys | |
import string | |
if __name__ == '__main__': | |
while True: | |
# Читаем построчно из входного потока. | |
line = sys.stdin.readline() | |
# Если читать больше нечего (конец файла --- `EOF`), | |
# то прерываем цикл. | |
if(not line): | |
break; | |
# Переводим считанную строку из двоичной системы счисления. | |
# В итоге получаем некоторое число --- номер символа. | |
number = string.atoi(line, 2) | |
# Получаем символ ASCII по его номеру. | |
char = chr(number) | |
# Записываем символ в выходной поток | |
sys.stdout.write(char) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env escript | |
%% -*- erlang -*- | |
%%! -smp enable -sname decoder | |
%% | |
%% Простая программа перевода двоичных октетов входного потока, | |
%% в байты выходного потока. На вход подаются строка, например: | |
%% 010010000110010101101100011011000110111100001010 | |
%% В результате работы программы она будет переведена в строку `Hello` | |
%% | |
main(_) -> | |
% Считываем 8 символов. | |
case io:get_chars('', 8) of | |
eof -> | |
% Если это конец файла, останавливаем программу. | |
init:stop(); | |
"\n" -> | |
% Если это перевод строки, то просто его выводим. | |
io:format("~n"); | |
String -> | |
% В противном случае, переводим строку в число. | |
Byte = erlang:list_to_integer(String, 2), | |
% Выводим число как символ. | |
io:format("~c", [Byte]), | |
% Повторяем цикл, вызывая функцию рекурсивно. | |
main([]) | |
end. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env escript | |
%% -*- erlang -*- | |
%%! -smp enable -sname decoder | |
%% | |
%% Простая и быстрая программа перевода двоичных октетов входного потока, | |
%% в байты выходного потока. На вход подаются строка, например: | |
%% 010010000110010101101100011011000110111100001010 | |
%% В результате работы программы она будет переведена в строку `Hello`. | |
%% WARNING: | |
%% Не пытайтесь дословно воспроизвести всю логику в программе на Си. | |
%% Erlang имеет иную парадигму программирования. | |
%% В отличие от Си он основан не на машине фон Неймана. | |
%% Однако, на уровне идеи логика будет сходной. | |
%% | |
main(_) -> | |
% Считываем 131072 символа (128 КиБ). | |
% На самом деле тут все равно сколько считывать. | |
% Но удобнее, если это число будет кратно количеству байт, | |
% представляющих закодированный символ. | |
case io:get_chars('', 131072) of | |
eof -> | |
% Если это конец файла, останавливаем программу. | |
init:stop(); | |
"\n" -> | |
% Если это перевод строки, то ничего не делаем, | |
% просто повторяем итерацию. | |
main([]); | |
Input -> | |
% Иначе разберем входную строку вручную, | |
% и получим перекодированную строку. | |
Output = parse(Input), | |
% Выведем строку как строку. | |
io:format("~s", [Output]), | |
% Повторяем итерацию. | |
main([]) | |
end. | |
%% | |
%% @doc Разбирает входной список символов и декодирует его. | |
%% @spec parse(list()) -> list(). | |
%% | |
parse(List) -> | |
parse(List, []). | |
%% | |
%% @doc Разбирает входной список символов и декодирует его. | |
%% Первый параметр это входной список, | |
%% во втором параметре накапливаются значения выходного списка. | |
%% Функция состоит из трех уравнений. | |
%% * Первое уравнение срабатывает если входной список пуст | |
%% (т.е. мы уже все разобрали). Тогда просто возвращаем выходной | |
%% список, предварительно перевернув его. | |
%% * Второе уравнение срабатывает, если мы встретили символ | |
%% перевода строки. Тогда откусываем, этот символ | |
%% от входного списка, во входной список следующей итерации | |
%% кладем то, что осталось, а выходной список | |
%% оставляем без изменения. | |
%% * Третье уравнение срабатывает, когда во входном списке есть, | |
%% восемь символов. Откусываем от входного списка восемь элементов, | |
%% кладем, что осталось во входной список следующей итерации. | |
%% Вычисляем результирующий символ по схеме Горнера | |
%% и добавляем его в начало выходного списка. | |
%% @spec parse(list(), list()) -> list(). | |
%% | |
parse([], Acc) -> | |
lists:reverse(Acc); | |
parse([$\n| Rest], Acc) -> | |
parse(Rest, Acc); | |
parse([X1,X2,X3,X4,X5,X6,X7,X8| Rest], Acc) -> | |
% Вычислим многочлен по основанию 2 по схеме Горнера. | |
Number = | |
( | |
( | |
( | |
( | |
( | |
( | |
( | |
( | |
( | |
( | |
( | |
( | |
convert(X1) | |
* 2 | |
) + convert(X2) | |
) * 2 | |
) + convert(X3) | |
) * 2 | |
) + convert(X4) | |
) * 2 | |
) + convert(X5) | |
) * 2 | |
) + convert(X6) | |
) * 2 | |
) + convert(X7) | |
) * 2 | |
+ convert(X8), | |
parse( | |
Rest, % Остаток входного списка. | |
[Number|Acc] % Добавка к выходному списку. | |
). | |
%% | |
%% @doc Переводит символ в число. | |
%% Просто отнимаем от входного символа код символа '0'. | |
%% @spec convert(integer()) -> integer() | |
%% | |
convert(X) -> | |
X - $0. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env escript | |
%% -*- erlang -*- | |
%%! -smp enable -sname decoder | |
%% | |
%% Простая и быстрая программа перевода 95-ичных пар входного потока, | |
%% в байты выходного потока. На вход подаются строка, например: | |
%% 2I1z2I1_2J1X2J1a0W2I1}2I1_2J1X0A | |
%% В результате работы программы она будет переведена в строку | |
%% `Миру мир!`. | |
%% WARNING: | |
%% Не пытайтесь дословно воспроизвести всю логику в программе на Си. | |
%% Erlang имеет иную парадигму программирования. | |
%% В отличие от Си он основан не на машине фон Неймана. | |
%% Однако, на уровне идеи логика будет сходной. | |
%% | |
-define(BASE, 95). | |
main(_) -> | |
% Считываем 32768 символа (32 КиБ). | |
% На самом деле тут все равно сколько считывать. | |
% Но удобнее, если это число будет кратно количеству байт, | |
% представляющих закодированный символ. | |
case io:get_chars('', 32768) of | |
eof -> | |
% Если это конец файла, останавливаем программу. | |
init:stop(); | |
"\n" -> | |
% Если это перевод строки, то ничего не делаем, | |
% просто повторяем итерацию. | |
main([]); | |
Input -> | |
% Иначе разберем входную строку вручную, | |
% и получим перекодированную строку. | |
Output = parse(Input), | |
% Выведем строку как строку. | |
io:format("~s", [Output]), | |
% Повторяем итерацию. | |
main([]) | |
end. | |
%% | |
%% @doc Разбирает входной список символов и декодирует его. | |
%% @spec parse(list()) -> list(). | |
%% | |
parse(List) -> | |
parse(List, []). | |
%% | |
%% @doc Разбирает входной список символов и декодирует его. | |
%% Первый параметр это входной список, | |
%% во втором параметре накапливаются значения выходного списка. | |
%% Функция состоит из трех уравнений. | |
%% * Первое уравнение срабатывает если входной список пуст | |
%% (т.е. мы уже все разобрали). Тогда просто возвращаем выходной | |
%% список, предварительно перевернув его. | |
%% * Второе уравнение срабатывает, если мы встретили символ | |
%% перевода строки. Тогда откусываем, этот символ | |
%% от входного списка, во входной список следующей итерации | |
%% кладем то, что осталось, а выходной список | |
%% оставляем без изменения. | |
%% * Третье уравнение срабатывает, когда во входном списке есть, | |
%% восемь символов. Откусываем от входного списка восемь элементов, | |
%% кладем, что осталось во входной список следующей итерации. | |
%% Вычисляем результирующий символ по схеме Горнера | |
%% и добавляем его в начало выходного списка. | |
%% @spec parse(list(), list()) -> list(). | |
%% | |
parse([], Acc) -> | |
lists:reverse(Acc); | |
parse([$\n| Rest], Acc) -> | |
parse(Rest, Acc); | |
parse([X1,X2| Rest], Acc) -> | |
% Вычислим многочлен по основанию BASE по схеме Горнера. | |
Number = ((convert(X1) * ?BASE) + convert(X2)), | |
parse( | |
Rest, % Остаток входного списка. | |
[Number|Acc] % Добавка к выходному списку. | |
). | |
%% | |
%% @doc Переводит символ в число. | |
%% Просто отнимаем от входного символа код символа | |
%% в зависимости от диапазона входного символа. | |
%% @spec convert(integer()) -> integer() | |
%% | |
convert(X) when $0 =< X, X =< $9 -> | |
X - $0; | |
convert(X) when $A =< X, X =< $Z -> | |
X - $A + 10; | |
convert(X) when $a =< X, X =< $z -> | |
X - $a + 36; | |
convert(X) when 32 =< X, X =< $/ -> | |
X - 32 + 62; | |
convert(X) when $: =< X, X =< $@ -> | |
X - $: + 78; | |
convert(X) when $[ =< X, X =< $` -> | |
X - $[ + 85; | |
convert(X) when ${ =< X, X =< $~ -> | |
X - ${ + 91; | |
convert(_) -> | |
% Если ни один из вариантов не срабатывает. | |
0. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment