Базовый преобразователь двоичного кода в восьмеричный

Я пишу базовый преобразователь, потому что скоро у меня будет тест, и мне нужно преобразовать двоичное число в 3 разных основания: восьмеричное, десятичное и шестнадцатеричное. Я уже написал код, преобразующий двоичную строку в десятичную и шестнадцатеричную.

function bintodec(Value:string;dec:TEdit;hexadec:TEdit): Integer;
 var             //dec and hexadec are the TEdits where I will put the result
  i, iValueSize: Integer;
  Edit2,f:TEdit;
begin
  Result := 0;
  iValueSize := Length(Value);
  for i := iValueSize downto 1 do
    begin
      if Value[i] = '1' then Result := Result + (1 shl (iValueSize - i));
    end;
  dec.Text:=(IntToStr(Result));        //dec. number
  hexadec.Text:=(IntToHex(Result,8));  //hexadec. number
end;

Как вы можете видеть здесь, функция принимает строку (например, 10101001) и помещает результат в 2 разных редактирования.

введите здесь описание изображения

Я сделал функцию, которая преобразует десятичное число в восьмеричное, но когда я нажимаю кнопку SpeedButton Calc., у меня возникает ошибка. В нем говорится, что проект1 вызвал исключение класса «Внешний: SIGSEGV», а затем рядом с Unit1 я вижу страницу control.inc. Я искал в Google решение, но не нашел полезных ответов.

function dec2oct(mystring:Integer): String;
  var
  a: String;
  getal_met_rest : Double;
  Edit2:TEdit;
  begin
    while mystring> 0 do
         begin
            getal_met_rest := getal / 8;
            a:= a + IntToStr(mystring - (trunc(getal_met_rest)*8));
            getal := trunc(getal_met_rest);
         end;
    dec2oct:=ReverseString(a);
    Edit2.text:=dec2oct
  end; 

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

var a:smallint;
begin
 bintodec(Edit1.Text,Edit3,Edit4);
 dec2oct(Edit3.Text); //Edit3 contains the number on base 10
end;

Не могли бы вы помочь мне?


person Alberto Rossi    schedule 27.05.2013    source источник
comment
Я бы предпочел, чтобы вы сказали нам, какой компилятор вы используете. Это не Delphi с SIGSEV.   -  person David Heffernan    schedule 28.05.2013
comment
Я использую Лазарус 1.0.8   -  person Alberto Rossi    schedule 28.05.2013
comment
Вы должны пометить вопрос соответствующим образом. Просто совет на будущее. Пометьте его delphi, и мы предполагаем, что это продукт Embarcadero.   -  person David Heffernan    schedule 28.05.2013
comment
Хорошо, спасибо, Дэвид за предложения, в следующий раз я отмечу Лазаря.   -  person Alberto Rossi    schedule 28.05.2013
comment
ОК, и убедитесь, что вы добавили обработку для 0, как я прокомментировал ваш принятый ответ.   -  person David Heffernan    schedule 28.05.2013
comment
Я снова добавил тег Delphi (в дополнение к тегу Lazarus), так как два из трех ответов могут применяться к обоим.   -  person Ken White    schedule 29.05.2013


Ответы (3)


Я бы обычно использовал строковые или символьные массивы и битовую арифметику для таких преобразований. Например:

function Int2Oct(invalue: integer): ShortString;
  const
    tt: array[0..7] of char = ('0', '1', '2', '3', '4', '5', '6', '7');
  var
    tempval: integer;
  begin
    Result := '';
    tempval := invalue;
    if tempval = 0 then
      Result := '0'
    else
      while (tempval <> 0) do
        begin
          Result := tt[(tempval and $7)] + Result;
          tempval := (tempval shr 3);
        end;
  end;

Кажется, работает за короткий промежуток времени, пока я его тестировал, если вы не ожидаете, что он будет обрабатывать отрицательные числа. Изменить: теперь он обрабатывает ноль.

person Glenn1234    schedule 27.05.2013
comment
@DavidHeffernan Согласен, и я узнал об этом около 20 минут назад. Это легко исправить, проверив нуль перед циклом и установив значение. Я отредактирую для этого. - person Glenn1234; 28.05.2013
comment
Сначала поставьте нулевую проверку и немедленно выйдите. Нет смысла назначать '', а потом передумать - person David Heffernan; 28.05.2013

Вот функция, которая работает примерно так же, как функция itoa библиотеки времени выполнения C, преобразуя положительное целочисленное значение (Cardinal в Delphi) в указанное основание счисления от 2 до 36. Она была протестирована в Delphi 2007 и XE4.

type
  TRadixRange = 2..36;

function ConvertIntToBase(value : Cardinal; Radix : TRadixRange) : string;
const
  Digits: array[0..35] of Char = ('0', '1', '2', '3',
                                  '4', '5', '6', '7',
                                  '8', '9', 'A', 'B',
                                  'C', 'D', 'E', 'F',
                                  'G', 'H', 'I', 'J',
                                  'K', 'L', 'M', 'N',
                                  'O', 'P', 'Q', 'R',
                                  'S', 'T', 'U', 'V',
                                  'W', 'X', 'Y', 'Z');
var
  nIndex : Integer;
begin
  Result := '';
  repeat
    nIndex := value mod radix;
    Result := Digits[nIndex] + Result;
    Value := Value div radix;
  until Value = 0;
end;

Ради интереса я решил написать функцию для «отмены» преобразования (преобразования из другой системы счисления обратно в десятичную (база 10)). Она также смоделирована (очень слабо) после функции C RTL atoi, за исключением того, что она требует, чтобы вы передавали систему счисления передаваемого числа.

function ConvertBaseToInt(const Value: string; const Radix: TRadixRange): Cardinal;
var
  i: Integer;
  Increment: Byte;
begin
  Result := 0;
  for i := 1 to Length(Value) do
  begin
    case Value[i] of
      '0'..'9': Increment := Ord(Value[i]) - Ord('0');
      'A'..'Z',
      'a'..'z': Increment := Ord(Value[i]) - Ord('A') + 10;
    else
      Increment := 0;
    end;
  end;
  Result := Result * Radix + Increment;
end;

Обратите внимание, что ConvertIntToBase был протестирован со многими числовыми входными данными, но я могу проверить только те основания, которые поддерживает калькулятор Windows в режиме программирования (двоичное (по основанию 2), восьмеричное (по основанию 8), десятичное (по основанию 10, которое я не тестировал) и hex (основание 16)), так как у меня нет калькулятора, который будет поддерживать другие значения системы счисления, и я не хочу выполнять эту работу вручную. ;-)

ConvertBaseToInt был протестирован путем передачи тестовых значений ConvertIntToBase и подтверждения того, что то, что входило в одно, было тем, что возвращалось из другого; IOW, что число, преобразованное в двоичное с помощью ConvertIntToBase, приведет к тому же числу при обратном прогоне через ConvertBaseToInt.

Вы можете проверить это с чем-то подобным в консольном приложении:

var
  TempStr: string;
  Reversed: Integer;
  i: Integer;
  Base: Byte;
const
  FmtStr = 'Value (base %d): %d  %s and back %d';
begin
  for i := 0 to 16 do
  begin
    for Base in [2, 8, 16] do  
    begin
      // Test bin, oct, and hex for a range of values from 0..65536
      TempStr := ConvertIntToBase(1 shl i, Base);
      Reversed := ConvertBaseToInt(TempStr, Base);
      Writeln(Format(FmtStr, [Base, 1 shl i, TempStr, Reversed]));
    end;
  end;
  Readln;
end.
person Ken White    schedule 28.05.2013
comment
+1 Мне это нравится. Никакой зависимости от степеней двойки или смещения. Правильное обращение с 0. - person David Heffernan; 28.05.2013
comment
+1, спасибо, Кен, ты ответил очень полезно. Я хотел бы спросить вас: я использую функцию StrToHex(myvalue,8) в качестве преобразователя. Ваш путь быстрее моего? - person Alberto Rossi; 28.05.2013
comment
@ Альберто, я понятия не имею. Я никогда не проверял их, и мой конвертирует числа в строку, а не строку в число. Преимущество моего в том, что он преобразует любое кардинальное число в любое основание одним вызовом функции; вам не нужно поддерживать отдельные. - person Ken White; 28.05.2013
comment
@DavidHeffernan: Спасибо. Надеюсь, вам тоже понравятся дополнения. :-) - person Ken White; 29.05.2013

program project1;

uses
    SysUtils, StrUtils;

begin
    // StrToInt function supports constants syntax: 
    // & - octal notation
    // $ - hexadecimal notation
    // % - binary notation
    Writeln(StrToInt('123'));
    Writeln(StrToInt('&173'))
    Writeln(StrToInt('$7B'));
    Writeln(StrToInt('%01111011'));

    // There are three functions for converting integer value to decimal, hexadecimal and binary notation
    Writeln(IntToStr(123));
    Writeln(IntToHex(123, 2));
    Writeln(intToBin(123, 8));

    Readln;
end.

Для других баз очень полезен ответ Кена Уайта.

Но в модуле StrUtils такие функции уже есть:

Dec2Numb
Synopsis: Convert a decimal number to a string representation, using given a base.
Declaration: function Dec2Numb(N: LongInt;Len: Byte;Base: Byte) : string
Visibility: default
Description: Dec2Numb converts N to its representation using base Base. The resulting string is left-padded
with zeroes till it has length Len. Base must be in the range 2-36 to be meaningful, but no checking
on this is performed.
Errors: If Base is out of range, the resulting string will contain unreadable (non-alphanumeric) characters.


Numb2Dec
Synopsis: Converts a string representation of a number to its numerical value, given a certain base.
Declaration: function Numb2Dec(S: string;Base: Byte) : LongInt
Visibility: default
Description: Numb2Dec converts the number in string S to a decimal value. It assumes the number is represented
using Base as the base. No checking is performed to see whether S contains a valid number using
base Base.
Errors: None.
person Abelisto    schedule 28.05.2013
comment
Пожалуйста, добавьте текст, чтобы объяснить это. Если бы вы это сделали, здесь мог бы быть отличный ответ. - person David Heffernan; 29.05.2013
comment
@DavidHeffernan Готово :) И добавлена ​​дополнительная информация. - person Abelisto; 30.05.2013
comment
Спасибо. Есть +1. Я бы все же предпочел текст, объясняющий код в ответе. - person David Heffernan; 30.05.2013
comment
Добавлены комментарии @DavidHeffernan в коде. Я действительно понятия не имею, как более четко объяснить этот очень простой пример кода. - person Abelisto; 30.05.2013
comment
Вы добавили комментарии с описанием функций, которыми не пользовались. Функции, которые вы использовали, откуда нам знать, что они делают? - person David Heffernan; 30.05.2013