Negativen Wert in Hexadezimal oder Binär umwandeln

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Negativen Wert in Hexadezimal oder Binär umwandeln

Beitrag von wp_xyz »

Muss das sein, dass du einen Anfänger mit PChar und pointer verwirrst? Es geht doch auch mit strinknormalen Indizes.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Negativen Wert in Hexadezimal oder Binär umwandeln

Beitrag von mse »

Mit normalen Indizes wird bei jeder Zeichenzuweisung ein String-unique-Test durchgeführt (copy on write) was der Performance nicht eben zuträglich ist.

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

Re: Negativen Wert in Hexadezimal oder Binär umwandeln

Beitrag von wp_xyz »

Das ist schon klar. Aber dem OP geht es nicht um das "beste" oder "schnellste" Verfahren, sondern darum, wie es überhaupt funktioniert. Und dazu ist die Optimierung mit PChar unnötig und für einen Anfänger extrem verwirrend. Er wird ohnehin auch schon an den SHR und AND Operationen zu knabbern haben.

Nixsager
Beiträge: 168
Registriert: Sa 8. Okt 2016, 08:38
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Wohnort: Polska

Re: Negativen Wert in Hexadezimal oder Binär umwandeln

Beitrag von Nixsager »

wp_xyz hat geschrieben:Er wird ohnehin auch schon an den SHR und AND Operationen zu knabbern haben.

Du sagt es.
wp_xyz hat geschrieben:Das ist schon klar. Aber dem OP geht es nicht um das "beste" oder "schnellste" Verfahren, sondern darum, wie es überhaupt funktioniert. Und dazu ist die Optimierung mit PChar unnötig und für einen Anfänger extrem verwirrend.

Genau. Ich will es erstmal verstehen wie es funktioniert. Optimieren kann man es noch immer, wenn ich das Prinzip und die Sprache besser verstehe.
Und wo ich bei verstehen bin, weiß ich nicht was die FP-IntToHex-Funktion soviel besser macht (abgesehen davon das sie auch mit negativen Werten funktioniert) bzw. wieso sie schneller ist. Aber das werden ich hoffentlich später verstehen.

Ich bin gerade mit Hilfe des Wiki-Links, am werkeln einer simplen/dummen Lösung.

Nachtrag:
Meine Idee ist für die Katz. :(
Das Problem ist ja, das ich keinen negativen Integer-Wert in einen Binärcode umwandeln kann kann.
Das einzige was mir einfällt ist, abfragen ob der Wert negativ ist, und wenn er es, den Abschnitt den ich zum umwandeln von Positiven Werten nutze irgendwie rückwärts laufen lasse. Irgendwo steckt da die Lösung drinne.
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Negativen Wert in Hexadezimal oder Binär umwandeln

Beitrag von theo »

Kleiner Denkanstoß:

Code: Alles auswählen

  ShowMessage(IntToStr(Cardinal(-1))); //oder writeln
  ShowMessage(IntToStr(Integer(-1)));   

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Negativen Wert in Hexadezimal oder Binär umwandeln

Beitrag von mse »

Wies funktioniert:
Zahlen in Computerprogrammen sind aus Bits zusammengesetzt. Ein Bit ist die kleinstmögliche Informationseinheit und kann nur zwei Zustände einnehmen, z.B. 0 oder 1. Übliche Zahlengrössen sind 8, 16, 32 und 64 Bits.
Um die Bits solcher Zahlen übersichtlich darzustellen werden jeweils vier Bits zu einem Zeichen zusammengefasst:

Code: Alles auswählen

 
 (0) 0000 -> 0
 (1) 0001 -> 1
 (2) 0010 -> 2
...
 (9) 1001 -> 9
(10) 1010 -> a
(11) 1011 -> b
...
(15) 1111 -> f
 
 

Die Tabelle

Code: Alles auswählen

 
const
 charhexlower: array[0..15] of char =
          ('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
 

macht diese Zuweisung.
Nun geht es noch darum, die einzelnen Vierergruppen auf die Zeichen im Ergebnisstring zu verteilen. z.B. für 32 Bit:

Code: Alles auswählen

 
Bitnummer    31..28  27..24 23..20 19..16 15..12 11..8  7..4  3..0
Beispiel       0001    0010   0011   0100   0101  0110  0111  1000
Wert              1       2      3      4      5     6     7     8 
Zeichennummer     0       1      2      3      4     5     6     7
 
Zeichennummer 01234567
Resultat     '12345678'
 

Die "shr" Operationen schieben jeweils eine Vierergruppe auf die
Bits 0..3, die "and $f" Operationen blenden alle anderen Bits aus, da $f = 0000000000001111 ist.

Die Bits einer Variablen können z.B. als positive Zahl oder als positiv/negativ-Ganzzahl interpretiert werden.
Im ersten Fall ist der Wertebereich einer 8-Bit Zahl 0..255. 0 ist dabei alle 8 Bits 0, 255 = 1+2+4+8+16+32+64+128 das heisst alle 8 Bits = 1.
Negative Zahlen werden im sogenannten Zweierkomplement dargestellt. Der positive Bereich ist zu den normalen Ganzzahlen identisch.
Um -1 darzustellen zieht man von 0 eins ab und kommt im Falle von 8 Bit zu 11111111. Das wird fortgeführt bis -128 = 10000000. -129 ergäbe 0111111 was mit +127 übereinstimmt und daher einen Überlauf bedeutet. Der Zweierkomplement Wertebereich einer 8-Bit Zahl ist daher -128..+127.

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

Re: Negativen Wert in Hexadezimal oder Binär umwandeln

Beitrag von wp_xyz »

Und hier noch die Umsetzung von mse's Verfahren in "normale" Strings mit Indices:

Code: Alles auswählen

 
const
 charhex: array[0..15] of char =
          ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
 charhexlower: array[0..15] of char =
          ('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
[...]
function valtohex(const avalue: byte): string;
begin
 setlength(result,2);
 result[1} := charhexlower[avalue shr 4];
 result[2] := charhexlower[avalue and $f];
end;
 
function valtohex(const avalue: word): string;
begin
 setlength(result,4);
 result[1] := charhexlower[avalue shr 12];
 result[2] := charhexlower[(avalue shr 8) and $f];
 result[3] := charhexlower[(avalue shr 4) and $f];
 result[4] := charhexlower[avalue and $f];
end;
 
function valtohex(const avalue: longword): string;
begin
 setlength(result,8);
 result[1] := charhexlower[avalue shr 28];
 result[2] := charhexlower[(avalue shr 24) and $f];
 result[3] := charhexlower[(avalue shr 20) and $f];
 result[4] := charhexlower[(avalue shr 16) and $f];
 result[5] := charhexlower[(avalue shr 12) and $f];
 result[6] := charhexlower[(avalue shr 8) and $f];
 result[7] := charhexlower[(avalue shr 4) and $f];
 result[8] := charhexlower[avalue and $f];
end;
 
function valtohex(const avalue: qword): string;
begin
 result:= valtohex(avalue shr 32)+valtohex(avalue);
end;

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

Re: Negativen Wert in Hexadezimal oder Binär umwandeln

Beitrag von wp_xyz »

Nixsager hat geschrieben:Das Problem ist ja, das ich keinen negativen Integer-Wert in einen Binärcode umwandeln kann kann.
Das einzige was mir einfällt ist, abfragen ob der Wert negativ ist, und wenn er es, den Abschnitt den ich zum umwandeln von Positiven Werten nutze irgendwie rückwärts laufen lasse. Irgendwo steckt da die Lösung drinne.

Natürlich kannst du das. Schau dir die Tabelle auf https://de.wikipedia.org/wiki/Zweierkomplement an. Da siehst du, dass ein und dasselbe Bitmuster einmal als positive und einmal als negative Zahl betrachtet werden kann. In dem Text steht, wie man die negative und positive Zahlen mit demselben Bitmuster ineinander umwandeln kann. Bestimme also die positive Zahl, die dasselbe Bitmuster hat wie deine negative und stecke die positive in deine Konvertierungsroutine. (oder lass das den Compiler machen, indem du deiner Routine einen vorzeichenLOSEN Integer-Typ übergibst).

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Negativen Wert in Hexadezimal oder Binär umwandeln

Beitrag von mse »

Die binäre Darstellung kann man z.B. so machen:

Code: Alles auswählen

 
function bintostr(inp: longword; digits: integer): string;
   //convert longword to binstring, digits = bit count
var
 int1: integer;
begin
 setlength(result,digits);
 for int1:= digits downto 1  do begin
  result[int1]:= char(ord('0') + (inp and $1));
  inp:= inp shr 1;
 end;
end;
 

Wie ich sehe gibt es da noch Optimierungsbedarf. ;-)

Nixsager
Beiträge: 168
Registriert: Sa 8. Okt 2016, 08:38
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Wohnort: Polska

Re: Negativen Wert in Hexadezimal oder Binär umwandeln

Beitrag von Nixsager »

Da bin ich dabei.
Mir ist nachdem ich den Post erweitert habe aufgefallen, dass ich den Binären Code nach dieser Methode nur umwandeln muss.
Dazu mache ich mir gerade erstmal eine For-Schleife mit If-Abfrage.

Und in der Rechenmethode, die ich im ersten Post geschrieben habe, habe ich ein If-Abfrage geschrieben die ein -1 in ein 1 umwandelt, Weil ich ja den Restwert direkt an einer String-Variabel weiter gebe.

@mse
Das mit shr und so, will erst machen wenn ich es kapiert habe.
Wenn meine Erweiterung funktioniert, werde ich sie posten, und dann könnt ihr den Kopf schütteln.
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

Nixsager
Beiträge: 168
Registriert: Sa 8. Okt 2016, 08:38
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Wohnort: Polska

Re: Negativen Wert in Hexadezimal oder Binär umwandeln

Beitrag von Nixsager »

So ich habe meinen Code erweitert.
Jetzt könnt ihr den Kopf schütteln.

Code: Alles auswählen

 
If NegativStatusValue = 1 then
   begin
      I := 32;
      Repeat
         If FirstZeroValue = 0 Then
            Case BinResultValueTemp[I] of
               '0':
                  CharValueTemp := '0';
               '1':
                  begin
                     CharValueTemp := '1';
                     FirstZeroValue := 1;
                  end;
            end
         else
            Case BinResultValueTemp[I] of
               '0':
                  CharValueTemp := '1';
               '1':
                  CharValueTemp := '0';
            end;
 
         BinResultValueTemp2 := CharValueTemp + BinResultValueTemp2;
         Dec(I);
      Until I = 0;
 
      BinResultValueTemp := BinResultValueTemp2;
   end;
 

Für Tipps zur optimierung ohne SHR und sowas wäre ich dankbar.
Es muss ich nur noch schauen wie ich das jetzt bei meiner IntToHex-Funktion umsetzte.

Ich habe mir von FP IntToBin und IntToHex angeschaut, weil ich wissen wollte wie schneller der Code im Vergleich zu meinem ist.
Die kann man nicht 1 zu 1 übernehmen. Denn TP hat kein SetLength und kein UInt32.
IntToHex scheint ansazuweise zu funktionieren, aber IntToBin funktioniert nicht.
Und davon mal abgesehen verstehe ich den Code nicht.

Danke nochmal an c18x37.
Daran gedacht hatte ich schon, sowas in der Richtung zu machen. Aber war gut das du mich in die Richtung weiter geschubst hast.
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

Antworten