Ответ в теме: Перевод из двоичной системы счисления в десятичную

      Комментарии к записи Ответ в теме: Перевод из двоичной системы счисления в десятичную отключены
#2131

Схематично перевод показан на рисунке. Точка разделяет число на дробную и целую части. Каждому разряду числа (a[i]) в соответствие ставится вес (weight), который для целой части рассчитывается как 2^i, а для дробной — 2^(-i-1), где i обозначает удаленность разряда от точки.
Для перевода числе достаточно вычислить сумму a[i]*weight[i].

Перевод целой и дробной частей осуществляется по-разному, поэтому целесообразно сразу разделить число части относительно точки. Если число представлено в виде строки — то удобно использовать функцию divide_list:

%% Number and parts introduce as strings
number_to_integral_fractional_parts(Number, Integral, Fractional):-
  divide_list(Number, [Integral, ".", Fractional]), !.
number_to_integral_fractional_parts(Integral, Integral, "").

Функция разделяет исходную строку на части относительно точки. Если точки нет, то число является целым — такой случай обрабатывается отдельно.

Так, как мы будем обрабатывать строки, а разряды нам надо обработать как числа (не как символы) — понадобится функция для преобразования символа двоичного числа в значение:

binaryDigitSymbolToValue(48, 0):-!.
binaryDigitSymbolToValue(49, 1):-!.

Код символа 48 соответствует символу «0», 49 — «1». Более правильно было бы не использовать значения кодов, а применить встроенную в SWI Prolog функцию char_code. Однако, программа без особого труда переносится в Turbo Prolog и Visual Prolog, поэтому чтобы не запутывать — я не стал применять встроенные функции.

Алгоритм перевода числа из двоичной системы счисления в десятичную можно записать так:

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

Тот же алгоритм на языке Prolog:

binary_to_decimal(Binary, Decimal):-
  number_to_integral_fractional_parts(Binary, IntegralBinary, FractionalBinary),
  integral_binary_to_decimal(IntegralBinary, IntegralDecimal),
  fractional_binary_to_decimal(FractionalBinary, FractionalDecimal),
  Decimal is IntegralDecimal + FractionalDecimal.

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

fractional_binary_to_decimal(Binary, Decimal):-
  fractional_binary_to_decimal(Binary, 2, Decimal).

fractional_binary_to_decimal([], _Weight, 0):-!.
fractional_binary_to_decimal([Digit|TailDigits], Weight, Decimal):-
  binaryDigitSymbolToValue(Digit, DigitValue),
  DigitDecimal is DigitValue / Weight,
  TailWeight is Weight * 2, 
  fractional_binary_to_decimal(TailDigits, TailWeight, TailDecimal),
  Decimal is TailDecimal + DigitDecimal.

На каждом шаге вычисляется десятичное значение разряда, посредством деления двоичного значения на вес. Вес увеличивается и рекурсивно вычисляется значение остальных разрядов. Затем значение первого разряда и хвоста складываются.

Аналогично выполняется обработка целой части, однако при вычислении значения разряда выполняется не деление, а умножение на вес. Кроме того, перед началом работы необходимо перевернуть исходное число, т.к. индексация разрядов происходит от младших разрядов, расположенных ближе к точке. Для реверса строки используется встроенная функция reverse.

integral_binary_to_decimal(Binary, Decimal):-
  reverse(Binary, DigitsBinary),
  integral_binary_to_decimal(DigitsBinary, 1, Decimal).
  
integral_binary_to_decimal([], _Weight, 0):-!.
integral_binary_to_decimal([Digit|TailDigits], Weight, Decimal):-
  binaryDigitSymbolToValue(Digit, DigitValue),
  DigitDecimal is DigitValue * Weight,
  TailWeight is Weight * 2, 
  integral_binary_to_decimal(TailDigits, TailWeight, TailDecimal),
  Decimal is TailDecimal + DigitDecimal.

Вложения: