【问题标题】:Base converter binary to octal基本转换器二进制到八进制
【发布时间】:2013-05-27 18:45:23
【问题描述】:

我正在编写一个基数转换器,因为我即将进行测试,我需要将二进制数转换为 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. 时出现错误。它说 project1 引发了一个类异常“外部:SIGSEGV”,然后在 Unit1 附近我看到了页面 control.inc。我在谷歌上搜索了一个解决方案,但没有找到有用的答案。

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;

你能帮帮我吗?

【问题讨论】:

  • 我希望您告诉我们您使用的是什么编译器。 SIGSEV 不是 Delphi。
  • 我使用的是 Lazarus 1.0.8
  • 您应该相应地标记问题。只是对未来的一些建议。将其标记为 delphi,我们假设是 Embarcadero 产品。
  • 好的,谢谢大卫的建议,下次我会标记拉撒路。
  • 好的,并确保为 0 添加处理,正如我对您接受的答案的评论。

标签: lazarus base-conversion


【解决方案1】:

我通常会使用字符串或字符数组以及位算术来进行此类转换。例如:

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;

只要您不希望它处理负数,它似乎可以在我测试它的短时间内工作。编辑:它现在处理零。

【讨论】:

  • @DavidHeffernan 同意,我在大约 20 分钟前发现了这一点。通过在循环之前检查零并设置值很容易修复。我会为此进行编辑。
  • 先验零,立即退出。分配''然后改变主意是没有意义的
【解决方案2】:

这里的函数有点像 C 运行时库的 itoa 函数,将正整数值(Delphi 中的 Cardinal)转换为 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,我做了不测试)和十六进制(以 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.

【讨论】:

  • +1 我喜欢这个。不依赖二的幂或转移。正确处理 0.
  • +1,谢谢肯,您的回答非常有用。我想问你一件事:我正在使用函数 StrToHex(myvalue,8) 作为转换器。你的方式比我的快吗?
  • @Alberto,我不知道。我从来没有对它们进行基准测试,我的将数字转换为字符串,而不是字符串转换为数字。我的优点是它可以通过单个函数调用将任何基数转换为任何基数;您不必维护单独的。
  • @DavidHeffernan:谢谢。希望你也喜欢这些补充。 :-)
【解决方案3】:
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.

对于其他基础,Ken White 的回答非常有用。

但在单元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.

【讨论】:

  • 请添加文字来解释这一点。如果你这样做,这里可能会有一个很好的答案。
  • @DavidHeffernan 完成 :) 并添加了一些附加信息。
  • 谢谢。有一个+1。我仍然希望用一些文字来解释答案中的代码。
  • @DavidHeffernan 添加了代码中的注释。我真的不知道如何更清楚地解释这个非常简单的代码示例。
  • 您添加了描述您未使用的函数的 cmets。你使用的函数,我们怎么知道它们是做什么的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 2015-12-12
  • 2014-06-10
  • 2017-09-27
  • 1970-01-01
  • 2015-09-15
相关资源
最近更新 更多