Restdivision (Dezimal in Binär) rechnen

Antworten
Benutzeravatar
Maik81SE
Beiträge: 260
Registriert: Fr 30. Sep 2011, 14:07
OS, Lazarus, FPC: Ubuntu18.04; Pi4 (Lazarusfpcupdeluxe/FPC trunk Lazarus 2.0.12)
CPU-Target: x64; arm; avr
Wohnort: Lübeck
Kontaktdaten:

Restdivision (Dezimal in Binär) rechnen

Beitrag von Maik81SE »

Moin zsm,

ich stehe gerade mal wieder auf dem Schlauch, bzw seh' den Wald vor lauter Bäumen nicht.

Gern lasse ich mich korrigieren, aber wenn ich das richtig auf dem Zettel habe bewirkt der Befehl mod eine Restdivision einer Dezimal-Zahl und der Befehl div eine Integer-Division.

Bsp.:

3 div 2 = 1
3 mod 2= 1

Also wenn ich nun meiner Lokig, die auch gerne mal einen Fehler aufweisen kann, folge sollte nachstehende Funktion auch einen Zahl entsprechend berechnen.

erste Version:

Code: Alles auswählen

procedure Set_LED(g, r, b: byte);
var a : byte;
begin
  for a:= 23 downto 0 do Data[a]:= '0';
  for a := 7 downto 0 do begin
    if (g mod 2) = 1 then Data[a] := '1';
    g  := g div 2;
    if (r mod 2) = 1 then Data[a+8] := '1';
    r  := r div 2;
    if (b mod 2) = 1 then Data[a+16] := '1';
    b  := b div 2;
    end;
end;
zweite Version: auf Varialbe g reduziert

Code: Alles auswählen

procedure Set_LED(g, r, b: byte);
var a, Rest, Temp : byte;
begin
  for a := 7 downto 0 do begin
    if Rest mod 2 = 0 then begin
      g := g div 2;
      Data[a] := '0';
      end
    else begin
      g := g div 2;
      Data[a] := '1';
      end;
    end;
end;
Aufgerufen wird dies via

Code: Alles auswählen

Set_LED(205, 2, 5);
die variable r und b lass ich erst mal außer acht

Via Terminal lass ich mir das Ergebnis als Kontrolle ausgeben.
Aber entgegen aller Logik erhalte ich bei dem Wert 205 den Binären Datenstrom 11111111 anstelle von 11001101

Zusatz-Informationen.

Diese soll auf allen gängigen MCUs laufen.

Ich wünsche euch ein entspanntes Weihnachtsfest.

mfg Maik

Code: Alles auswählen

label.caption:= 'gnublin.no-ip.info'
Debian 10.6 with Lazarus 2.1.0 r64080 & FPC 3.0.4 x86_64-linux-gkt2&Code:Blocks
Ubuntu 18.10 Studio
Pi4 -> Lazarus-IDE v2.0.0+dfsg-2 rDebian Package .0.0+dfsg-2[ & FPC 3.0.4

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

Re: Restdivision (Dezimal in Binär) rechnen

Beitrag von Winni »

Hi!

Die Variable Rest wird nirgends initialisiert und kann irgendeinen zufälligen Wert annehmen .

Winni

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

Re: Restdivision (Dezimal in Binär) rechnen

Beitrag von Winni »

Hi!

Ich glaube zu ahnen, was Du wolltest:

Code: Alles auswählen

procedure Set_LED(g, r, b: byte);
var a: byte;
begin
  for a := 7 downto 0 do begin
   Data[a] := IntToStr(g mod 2);
   g := g div 2;    
   end; // for
end;

Hab ich richtg geraten????

Winni

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

Re: Restdivision (Dezimal in Binär) rechnen

Beitrag von wp_xyz »

Maik81SE hat geschrieben:
Do 23. Dez 2021, 21:37
bewirkt der Befehl mod eine Restdivision einer Dezimal-Zahl und der Befehl div eine Integer-Division.
Das ist etwas "verwirrend" ausgedrückt, so dass mir nicht klar ist, ob du das richtig verstanden hast. Daher schulmeisterlich nochmal ganz von vorne:

Wenn du zwei Integerzahlen durcheinander dividierst, erzeugt der Operator "div" das ganzzahlige Ergebnis und "mod" den Rest. 16 dividiert durch 5 ist 3 mit Rest 1: 16 div 5 => 3; 16 mod 5 => 1.

Man kann auch beides gemeinsam berechnen lassen: procedure DivMod(a, b, ergebnis, rest), in dem Beispiel DivMod(16,5, erg, rest) wäre erg = 3 und rest = 1 (16 = 3*5 + 1)

Den "mod" Operator gibt es seit FPC 3.2 analog auch für Gleitkommazahlen: 3.4 mod 1.1 = 0.1 (3.4 = 3*1.1 + 0.1). Ich meine mich aber zu erinnern, dass es hier irgendwo Unstimmigkeiten gab, evtl mit negativen Zahlen...

Benutzeravatar
kupferstecher
Beiträge: 373
Registriert: Do 17. Nov 2016, 11:52

Re: Restdivision (Dezimal in Binär) rechnen

Beitrag von kupferstecher »

Hallo Maik,

deine erste Version sieht eigentlich richtig aus. Bei der zweiten stimmt was mit der Variablen "Rest" nicht, wie Winni schon sagte.

Allerdings würde ich statt der Modulooperation eine logische Verknüpfung verwenden.
if (g and 1) > 0 then ...

Für mich wäre das lesbarer, weil solche Bitabfragen in Embedded-Code häufig vorkommt. Ist aber wohl Geschmacksache, ich würde vermuten, dass der Compiler den gleichen Code erzeugt.

In echter "Embedded-Manier" gäbe es noch eine kompakte Variante mit Shiftoperationen:

Code: Alles auswählen

procedure Set_LED(g, r, b: byte);
var a : byte;
begin
  for a := 0 to 7 do begin
    if (g and (1 shl a)) > 0
    then Data[7-a] := '1' else Data[7-a] := '0';
end;
Sieht für das ungewohnte Auge vielleicht unleserlich aus, (1 shl n) ist aber ein Standardkonstrukt für "das n-te Bit".

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

Re: Restdivision (Dezimal in Binär) rechnen

Beitrag von siro »

Die erste Variante der Software funktioniert bei mir,
!! vorausgesetzt: "Data" ist ein Array[0..23] of Char;
sollte es ein String oder ShortString sein, geht es schief.

Die zweite geht natürlich nicht, wie schon erwähnt wurde:
Rest wird weder initialisiert, noch ändert sich der Wert von Rest innerhalb der Procedure.
Angenommen Rest stünde auf 255 dann kommt bei Variante 2 deines Codes auch 11111111 raus.

Wenn Du in der 2ten Variante die Zeile

Code: Alles auswählen

if Rest MOD 2 
auf

Code: Alles auswählen

if g MOD 2

änderst, dann funktioniert deine Testversion auf für den Wert "g".

Hinweis:
Wenn es möglichst universell für verschiedene Controller sein soll, bin ich kein Freund von MOD und DIV,
da ich damit böse auf die Nase gefallen bin. Auf einem 32 Bit Controller lief meine Funktion mit MOD und DIV
völlig einwandfrei, bis ich selbige Funktion auf einem 16 Bit Controller laufen lies.
MOD und DIV war auf die Bitbreite (Standard Integer) des Controllers festgelegt und da ich MOD und DIV auf einen 32 Bit Wert für einen 16 Bit Controller
angewandt hatte, war das Ergebnis leider nicht immer korrekt. Ich weis aber nicht wie das beim FPC ist, ob er dann den richtigen Code erzeugt.
Hier würde ich auch lieber die Proceduren DivMod wie wp_xyz schon schrieb, benutzen. Diese ist für verschiedene Datentypen entsprechend ausgelegt.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Benutzeravatar
Maik81SE
Beiträge: 260
Registriert: Fr 30. Sep 2011, 14:07
OS, Lazarus, FPC: Ubuntu18.04; Pi4 (Lazarusfpcupdeluxe/FPC trunk Lazarus 2.0.12)
CPU-Target: x64; arm; avr
Wohnort: Lübeck
Kontaktdaten:

Re: Restdivision (Dezimal in Binär) rechnen

Beitrag von Maik81SE »

siro hat geschrieben:
Fr 24. Dez 2021, 09:31
Die erste Variante der Software funktioniert bei mir,
!! vorausgesetzt: "Data" ist ein Array[0..23] of Char;.
bei AVR arbeite ich aus Prinzip mit Char
siro hat geschrieben:
Fr 24. Dez 2021, 09:31
Wenn Du in der 2ten Variante die Zeile

Code: Alles auswählen

if Rest MOD 2 
auf

Code: Alles auswählen

if g MOD 2

änderst, dann funktioniert deine Testversion auf für den Wert "g".
Blindfisch :lol: Den hab ich echt nicht gesehen...
entspräche ja aber auch der Funktion
kupferstecher hat geschrieben:
Do 23. Dez 2021, 23:22

Code: Alles auswählen

if (g and (1 shl a)) > 0
kupferstecher hat geschrieben:
Do 23. Dez 2021, 23:22
Hallo Maik,

deine erste Version sieht eigentlich richtig aus. Bei der zweiten stimmt was mit der Variablen "Rest" nicht, wie Winni schon sagte.

Allerdings würde ich statt der Modulooperation eine logische Verknüpfung verwenden.
if (g and 1) > 0 then ...

Für mich wäre das lesbarer, weil solche Bitabfragen in Embedded-Code häufig vorkommt. Ist aber wohl Geschmacksache, ich würde vermuten, dass der Compiler den gleichen Code erzeugt.

In echter "Embedded-Manier" gäbe es noch eine kompakte Variante mit Shiftoperationen:

Code: Alles auswählen

procedure Set_LED(g, r, b: byte);
var a : byte;
begin
  for a := 0 to 7 do begin
    if (g and (1 shl a)) > 0
    then Data[7-a] := '1' else Data[7-a] := '0';
end;
Sieht für das ungewohnte Auge vielleicht unleserlich aus, (1 shl n) ist aber ein Standardkonstrukt für "das n-te Bit".
Hab diese abenfalls mal versucht, jedoch mit dem Effekt, das es das die Ausgabe selbst bei der Zahl 128 auf 11111111 erfolgt.
Ich hab bald den verdacht, das es in der Unit übergreifende Übergabe schiefgeht.

Funktion wie IntToStr, DivMod und Co kann ich leider auch nicht anwenden, da diese meines Wissens nicht auf MCUs laufen.
Vielleicht denk ich auch gerade zu Quer zw. PC und AVR

Ich leg euch mal das File mit rein,
Da sind auch gleich alle Setting enthalten.
Dateianhänge
NeoTest_AVR5.zip
(32.84 KiB) 27-mal heruntergeladen

Code: Alles auswählen

label.caption:= 'gnublin.no-ip.info'
Debian 10.6 with Lazarus 2.1.0 r64080 & FPC 3.0.4 x86_64-linux-gkt2&Code:Blocks
Ubuntu 18.10 Studio
Pi4 -> Lazarus-IDE v2.0.0+dfsg-2 rDebian Package .0.0+dfsg-2[ & FPC 3.0.4

Benutzeravatar
Maik81SE
Beiträge: 260
Registriert: Fr 30. Sep 2011, 14:07
OS, Lazarus, FPC: Ubuntu18.04; Pi4 (Lazarusfpcupdeluxe/FPC trunk Lazarus 2.0.12)
CPU-Target: x64; arm; avr
Wohnort: Lübeck
Kontaktdaten:

[gelöst]: Restdivision (Dezimal in Binär) rechnen

Beitrag von Maik81SE »

Eine Nacht noch mal drüber geschlafen und eben fiel es mit wie schuppen von den Augen.
Der Fehlerteufel lag echt im Deteils...

auch wenn man über diese Art des Debugens geteilter Meinung sein kann, aber diese Art hilft mir immer wieder wenn ich zu blind bin.

Code: Alles auswählen

      UARTSendChar(Data[a]);

Code: Alles auswählen

label.caption:= 'gnublin.no-ip.info'
Debian 10.6 with Lazarus 2.1.0 r64080 & FPC 3.0.4 x86_64-linux-gkt2&Code:Blocks
Ubuntu 18.10 Studio
Pi4 -> Lazarus-IDE v2.0.0+dfsg-2 rDebian Package .0.0+dfsg-2[ & FPC 3.0.4

Antworten