Binärzahl in Dezimalzahl

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
benderboxer
Beiträge: 12
Registriert: Sa 21. Dez 2019, 20:55

Binärzahl in Dezimalzahl

Beitrag von benderboxer »

Hallo Zusammen,

ich habe die Aufgabe bekommen in Lazarus ein Binärzahlen-Tester zu programmieren.
Dabei benutze ich das erste mal Funktionen.
So wie es gerade aussieht ist da wohl einiges Schief gelaufen... Kann mich vielleicht einer von euch verbessern?

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var binzahl: string;
begin
  binzahl := Edit1.Text;

  function binzahltest(bz:string):string;
  var bz, ergebnis: string; i, erg: integer;
  begin
    anzahl := length(bz);
    ergebnis := true;
    for i := 1 to anzahl do
    begin
      if bz[i] = '0' or bz[i] = '1' then
      begin
        binzahltest := true;
        erg := bz[i];
      end
      else
      begin
        binzahltest := false;
      end;
    end;
  end;

  if binzahltest(binzahl) = true then
  begin
    function umrechnen(bin:string):integer;
    var i, anz, stelle, s, zweierpotenz, umrechnen: integer;
    begin
      anz := length(bin);
      i := anz;
      zweierpotenz := 1;
      s := 0;
      while i > 0 do
      begin
        stelle := bin[i];
        s := s + stelle * zweierpotenz;
        zweierpotenz := zweierpotenz * 2;
        i := i - 1;
      end;
      umrechnen := s;
    end;
  end;
end;      
Das Struktogramm dazu:
Bild
Bild
Bild

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Binärzahl in Dezimalzahl

Beitrag von Winni »

Hallo!

Bei der Überprüfung des Strings klapperst Du den ganzen String ab - auch wenn schon ein Fehler passiert ist. Bei Deiner Routine flutscht ein String wie '01X01' ducrh, weil am Ende ein korrekter Wert steht.

Mach das doch so:

Code: Alles auswählen

var OK: boolean = true;
.... 

While (i <= anzahl) and ok do
  begin
  ok  := bz[i] in ['0','1'];
  if ok then inc(i);
  end;// While;
result := OK;
Winni

sstvmaster
Beiträge: 575
Registriert: Sa 22. Okt 2016, 23:12
OS, Lazarus, FPC: W10, L 2.2.6
CPU-Target: 32+64bit
Wohnort: Dresden

Re: Binärzahl in Dezimalzahl

Beitrag von sstvmaster »

@Winni

Das wäre schon Richtig, aber in der Aufgabenstellung soll das mit "if ... then" gelöst werden.
Die haben den "in" Operator sicherlich noch nicht gehabt.
LG Maik

Windows 10,
- Lazarus 2.2.6 (stable) + fpc 3.2.2 (stable)
- Lazarus 2.2.7 (fixes) + fpc 3.3.1 (main/trunk)

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Binärzahl in Dezimalzahl

Beitrag von wp_xyz »

Wird der Code überhaupt vom Compiler akzeptiert? Meines Wissens ist es nicht möglich innerhalb eines begin-end Blocks eine Funktion zu implementieren. Solcher Unsinn wird zwar immer wieder gefordert, hat aber noch nicht Einzug in Free Pascal gefunden.

Ich meine, statt

Code: Alles auswählen

procedure TForm1.ButtonClick(Sender: TObject);
begin

  function binzahltest(bz: String): String;   // Implementierung *IM* begin-end Block
  begin
  ...
  end;
 
 if binzahltest(...).... then begin
   ...
  end;
end;
müsste es heißen

Code: Alles auswählen

procedure TForm1.ButtonClick(Sender: TObject);

  function binzahltest(bz: String): String;    // Implementierung *VOR* dem "begin" der Prozedur, vor oder nach der Deklaration lokaler Variablen
  begin
  ...
  end;
  
begin
  if binzahltest(...) then begin
  ...
  end;  
end;
oder, falls nichts aus der Klasse TForm1 und keine lokale Variale von ButtonClick benutzt wird

Code: Alles auswählen

function binzahltest(bz: String): String;  // Implementierung *AUßERHALB* der Prozedur
begin
  ...
end;

procedure TForm1.ButtonClick(Sender: TObject);
begin
  if binzahltest(...) then begin
  ...
  end;
end;

benderboxer
Beiträge: 12
Registriert: Sa 21. Dez 2019, 20:55

Re: Binärzahl in Dezimalzahl

Beitrag von benderboxer »

Oh je... jetzt werden bei mir viel mehr Fehler geschmissen....

Folgender Code:

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
function binzahltest(bz:string):string;
var ergebnis: string; i, anzahl, erg: integer;
begin
  anzahl := length(bz);
  ergebnis := true;
  for i := 1 to anzahl do
  begin
    if bz[i] = '0' or bz[i] = '1' then
    begin
      binzahltest := true;
      erg := bz[i];
    end
    else
    begin
      binzahltest := false;
    end;
  end;
end;
function umrechnen(bin:string):integer;
var i, anz, stelle, s, zweierpotenz, umrechnen: integer;
begin
  anz := length(bin);
  i := anz;
  zweierpotenz := 1;
  s := 0;
  while i > 0 do
  begin
    stelle := bin[i];
    s := s + stelle * zweierpotenz;
    zweierpotenz := zweierpotenz * 2;
    i := i - 1;
  end;
  umrechnen := s;
end;
var binzahl: string;
begin
  binzahl := Edit1.Text;



  if binzahltest(binzahl) = true then
  begin
     Label1.Caption := 'Yes';
     Label1.Visible := true;
  end;
end;

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Binärzahl in Dezimalzahl

Beitrag von wp_xyz »

Nachdem das ganze überschaubar ist, habe ich mir die Mühe gemacht, deinen Code in ein kleines Projekt einzufügen und den Compiler um Hilfe gebeten.

Nachdem das Projekt fertig zusammengeklickt war, habe ich versucht es zu kompilieren und der Compiler hat eine Vielzahl von Fehlern bemerkt. Diese sind alle im Nachrichtenfenster aufgelistet. Klicke die Meldungen Zeile für Zeile an, und der Editor springt an die entsprechende, bemängelte Quelltest-Stelle.

1. Fehler in "binzahltest", Zeile "ergebnis := true": Im Nachrichtenfenster steht: "Incompatible types: got 'boolean', expected 'AnsiString'". Der cursor steht auf "true" - also mag der Compiler hier das "true" nicht. Und das ist klar, denn du hast zwei Zeilen höher die Variable "ergebnis" als String deklariert - ein String kann nicht true oder false werden, das ist reserviert für den Datentyp boolean. Also: geh' in dich, und überleg dir, was "ergebnis" sein soll. Und übrigens wird "ergebnis" in der ganzen "binzahltest" Routine nicht verwendet; daher habe ich die Zeile auskommentiert, um weiterzukommen.

2. Fehler: "if bz[ i] = '0' or bz[ i] = '1' then". Hier ist die Fehlermeldung wahrscheinlich verwirrend: "Operator not overloaded "Char" or "Char"". Dazu musst du wissen, dass der Operator "or" stärker ist als der Vergleichsoperator ("="). Die "or"-Verknüpfung zwischen die beiden Char-Größen "0" und bz[ i] ist aber gar nicht definiert. (Und wenn sie es wäre, käme das nächste Problem, dass da ein drei-gliedriger Vergleich stehen würde, wie "if a = b =c", den gibt es auch nicht). Solche Problem kannst du vermeiden, wenn du die mit "or" oder "and" verknüpften Ausdrücke immer in Klammern setzt. Damit wird das "o" eine verknüpfung von zwei boolschen Ausdrücken und macht kein Problem mehr. Also: "if (bz[ i] = '0') or (bz[ i] = '1') then".

3. Problem: "binzahltest := true" - wie oben unter 1: Die Funktion "binzahltest" ist so deklariert, dass sie einen String zurückliefern soll, du gibst dem Ergebnis aber einen booleschen Wert, dasselbe passiert auch ein paar Zeilen tiefer. Ich habe deinen Algorithmus nicht studiert, aber möglicherweise ist einfach die Funktion falsch deklariert und soll einen booleschen Wert zurückgeben.

4. Problem: "erg := bz[ i]" - "incompatible types: got "char" expected "longint"": "erg" ist deklariert als integer, bz ist ein String, also ist bz[ i] ein Char. Das passt nicht zusammen (übrigens wird auch "erg" nicht weiterverwendet)

5. Problem: "Duplicate Identifier "UMRECHNEN"". Das ist in der nächsten Funktion "Umrechnen(bin:string): integer". Hier hast du im "var"-Abschnitt eine lokale Variable deklariert, die denselben Namen trägt wie die Funktion. Das geht nicht. Nenne eins von den beiden anders.

usw.

Also: Jede Fehlermeldung des Compilers ist ein Hinweis, dass etwas falsch ist, und im Nachrichtenfenster steht, was falsch ist (leider ist die Meldung nicht immer klar zu verstehen...)

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1430
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Binärzahl in Dezimalzahl

Beitrag von fliegermichl »

wp_xyz hat geschrieben:
Di 12. Mai 2020, 23:50

Also: Jede Fehlermeldung des Compilers ist ein Hinweis, dass etwas falsch ist, und im Nachrichtenfenster steht, was falsch ist (leider ist die Meldung nicht immer klar zu verstehen...)
Da gebe ich dir Recht. Wobei die Fehlerausgaben des Free Pascal Compilers gar nicht so schlecht sind. Ich hatte mal das Pech ein größeres Perl Projekt betreuen zu müssen. Da hat man das Gefühl, dass der beim kleinsten typo ein chinesisches Buch ausspuckt.

Judas
Beiträge: 15
Registriert: Mo 26. Mär 2012, 14:36

Re: Binärzahl in Dezimalzahl

Beitrag von Judas »

Moin,

ich habe dein kleines Programm einmal in eine funktionierende Form gebracht. Solltest du das Ganze im Rahmen einer Schulaufgabe verwenden, solltest du vorher versuchen, den Code auch zu verstehen. Nicht, dass du rote Ohren bekommst. ;-)

Code: Alles auswählen

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1      : TButton;
    Edit1        : TEdit;
    labelErgebnis: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Edit1Change(Sender: TObject);
  private
    function Binzahltest(BinaryString: string): boolean;
    function Umrechnen(const BinaryString: string): integer;
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}


{ TForm1 }

function TForm1.BinZahlTest(BinaryString: string): boolean;
var
  Count,
  Anzahl  : integer;
  isBinary: Boolean;
begin
  anzahl := length(BinaryString);
  Count := 0;

  repeat
    inc(Count);
    isBinary := (BinaryString[Count] = '0') or (BinaryString[Count] = '1');
  until Not isBinary or (Count = Anzahl);

  Result := isBinary;
end;

function TForm1.Umrechnen(const BinaryString: string): integer;
var
  s,
  Indicator,
  Zweierpotenz: integer;
begin
  Indicator := length(BinaryString);
  zweierpotenz := 1;
  s := 0;

 while Indicator > 0 do
  begin
    inc(s, StrToInt(BinaryString[Indicator]) * Zweierpotenz);
    Zweierpotenz := Zweierpotenz * 2;
    dec(Indicator);
  end;

  Result := s;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Binaerzahl: integer;
Begin
  Binaerzahl := Umrechnen(Trim(Edit1.Text));
  LabelErgebnis.Caption := IntToStr(Binaerzahl);
end;

procedure TForm1.Edit1Change(Sender: TObject);
var
  s: string;
begin
  s := trim(Edit1.text);

  Button1.enabled := (length(s) > 0) and Binzahltest(s);
  LabelErgebnis.Caption := '';
end;

end.


siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Binärzahl in Dezimalzahl

Beitrag von siro »

Da der Judas schon eine "fertige" Lösung gepostet hat,
kann ich meinen Versuch von gestern ja nun auch posten,
Ich hatte es bewusst zurück gehalten um die Kreativität des Posters nicht zu beeinfussen...

Wie man sieht: viele Wege führen zum Ziel...

Code: Alles auswählen

function Check(s:string):Integer;
var i:Integer;
begin
  for i:=1 to length(s) do
    if (s[i] <> '0') and (s[i] <> '1') then begin
      result:=i;  // Fehlerposition zurück geben
      exit;       // fertig
    end;
  result:=0;      // kein Fehler
end;

function Calculate(s:string):Integer;
var n,i:integer;
begin
  result:=0;
  n:=1;
  for i:=length(s) downto 1 do begin    // von rechts nach links
    if s[i] = '1' then
      result:=result+n;
    n := n shl 1;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var value:String; Fehler:Integer;
begin
  value:='10011010010';     // sollte 1234 ergeben
  Fehler:=Check(value);
  if Fehler = 0 then caption:=IntToStr(Calculate(value))
                else caption:='Fehler an Position: ' + IntToStr(Fehler);
end;                
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Binärzahl in Dezimalzahl

Beitrag von Mathias »

Du hast mir gerade etwas interessantes gezeigt, den Befehl Trim kannte ich noch nicht.

Code: Alles auswählen

s := trim(Edit1.text);
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: Binärzahl in Dezimalzahl

Beitrag von Timm Thaler »

Ich will euch ja den Spass nicht verderben, aber:

Code: Alles auswählen

isbinary := TryStrToInt('%' + binzahl, erg);

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Binärzahl in Dezimalzahl

Beitrag von Winni »

Mathias hat geschrieben:
Do 14. Mai 2020, 16:51
Du hast mir gerade etwas interessantes gezeigt, den Befehl Trim kannte ich noch nicht.

Code: Alles auswählen

s := trim(Edit1.text);
Trim hat Turbo-Pascal von Basic geklaut.
Those were the days ......

Winni

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Binärzahl in Dezimalzahl

Beitrag von Winni »

Timm Thaler hat geschrieben:
Do 14. Mai 2020, 23:17
Ich will euch ja den Spass nicht verderben, aber:

Code: Alles auswählen

isbinary := TryStrToInt('%' + binzahl, erg);
Hallo!
Das hab ich mir die ganze Zeit verkniffen.

Aber nun kann benderboxer ja mal in der Implementierung nachsehen, ob sie auch brav nach seinem Struktogramm gearbeitet haben.

Winni

Antworten