Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Zwei Werte [0..16] in einem Integer festhalten (https://www.delphipraxis.net/151381-zwei-werte-%5B0-16%5D-einem-integer-festhalten.html)

Lannes 15. Mai 2010 14:43

Re: Zwei Werte [0..16] in einem Integer festhalten
 
Hallo,

da es noch nicht erwähnt wurde, es gibt auch MakeLong() und MakeWord()

Delphi-Quellcode:
var w: Word;
    b1, b2: Byte;
begin
  b1 := 44;
  b2 := 55;
  w := MakeWord(b1, b2);
//auslesen
  b1 := LoByte(w);
  b2 := HiByte(w);
Delphi-Quellcode:
var i: Integer;
    w1, w2: Word;
begin
  w1 := 4444;
  w2 := 5555;
  i := MakeLong(w1, w2);
//auslesen
  w1 := LoWord(i);
  w2 := HiWord(i);

divBy0 15. Mai 2010 15:52

Re: Zwei Werte [0..16] in einem Integer festhalten
 
Zitat:

Zitat von himitsu
@divBy0: 1..16 paßt sogar bis zu 8 Mal in einen Interger rein.

bzw. ein Integer (4-Byte) läßt sich mit 8 Hexadezimalstellen (Base16) darstellen.

Ja, das stimmt natürlich. Ich hatte dies selbst sogar schon mal genutzt... :oops:

himitsu 15. Mai 2010 16:56

Re: Zwei Werte [0..16] in einem Integer festhalten
 
Notfalls hätte ich noch etwas:
Delphi-Quellcode:
Var P: TIntegerPack;

P.Clear;
P.Add(MIN_X, MAX_X, X);
P.Add(MIN_Y, MAX_Y, Y);
i := P.Result;

P.Clear;
P.Add(MIN_X, MAX_X);
P.Add(MIN_Y, MAX_Y);
P.Result := i;
X := P.Value[0];
Y := P.Value[1];
Das Ergebnis dürfte Binär die kleinste Darstellung ergeben. :gruebel:

Delphi-Quellcode:
uses
  SysConst, RTLConsts, SysUtils;

const
  MinInt = Low(Integer);

type
  TIntegerPack = Record
  Private
    FList: Array of Record
              Min, Max: Integer;
              Value:   Integer;
            End;
    FResult: UInt64;
    FResSize: UInt64;
    Function GetMin  (Index:   Integer): Integer;
    Function GetMax  (Index:   Integer): Integer;
    Function GetVal  (Index:   Integer): Integer;
    Procedure SetVal  (Index, X: Integer);
    Procedure SetResult(       X: UInt64);
    Function GetSize (Bits:    Integer): Integer;
  Public
    Function Add(Min, Max: Integer; Value: Integer = MinInt): Integer;
    Property Min [Index: Integer]: Integer Read GetMin;
    Property Max [Index: Integer]: Integer Read GetMax;
    Property Value[Index: Integer]: Integer Read GetVal Write SetVal;

    Property Result: UInt64          Read FResult Write SetResult;
    Property ResSize: UInt64          Read FResSize;
    Property Bytes:  Integer Index 8 Read GetSize;
    Property Bits:   Integer Index 1 Read GetSize;

    Procedure Clear;
  End;

Function TIntegerPack.GetMin(Index: Integer): Integer;
  Begin
    If Cardinal(Index) >= Length(FList) Then
      Raise Exception.CreateResFmt(@SListIndexError, [Index]);
    Result := FList[Index].Min;
  End;

Function TIntegerPack.GetMax(Index: Integer): Integer;
  Begin
    If Cardinal(Index) >= Length(FList) Then
      Raise Exception.CreateResFmt(@SListIndexError, [Index]);
    Result := FList[Index].Max;
  End;

Function TIntegerPack.GetVal(Index: Integer): Integer;
  Begin
    If Cardinal(Index) >= Length(FList) Then
      Raise Exception.CreateResFmt(@SListIndexError, [Index]);
    Result := FList[Index].Value;
  End;

Procedure TIntegerPack.SetVal(Index, X: Integer);
  Begin
    If Cardinal(Index) >= Length(FList) Then
      Raise Exception.CreateResFmt(@SListIndexError, [Index]);
    If (X < FList[Index].Min) or (X > FList[Index].Max) Then
      Raise Exception.CreateRes(@SArgumentOutOfRange);
    FList[Index].Value := X;

    FResult := 0;
    For Index := High(FList) downto 0 do
      With FList[Index] do
        FResult := FResult * Cardinal(Max - Min + 1) + Cardinal(Value - Min);
  End;

Procedure TIntegerPack.SetResult(X: UInt64);
  Var Index: Integer;

  Begin
    For Index := 0 to High(FList) do
      With FList[Index] do Begin
        Value := X mod Cardinal(Max - Min + 1) + Min;
        X    := X div Cardinal(Max - Min + 1);
      End;
    //If X <> 0 Then Raise ...;
    FResult := 0;
    For Index := High(FList) downto 0 do
      With FList[Index] do
        FResult := FResult * Cardinal(Max - Min + 1) + Cardinal(Value - Min);
  End;

Function TIntegerPack.GetSize(Bits: Integer): Integer;
  Var X: UInt64;

  Begin
    Result := 0;
    X := FResSize;
    While X <> 0 do Begin
      X := X shr Bits;
      Inc(Result);
    End;
  End;

Function TIntegerPack.Add(Min, Max: Integer; Value: Integer = MinInt): Integer;
  Var Index: Integer;
    X, T:  Int64;

  Begin
    Result := Length(FList);
    SetLength(FList, Result + 1);
    Try
      FList[Result].Min := Min;
      FList[Result].Max := Max;

      X := 1;
      For Index := High(FList) downto 0 do
        With FList[Index] do Begin
          T := X;
          X := X * Cardinal(Max - Min + 1);
          If X div Cardinal(Max - Min + 1) <> T Then
            Raise EIntOverflow.CreateRes(@SIntOverflow);
        End;
      FResSize := X;
    Except
      SetLength(FList, High(FList));
      Raise;
    End;
    If Value = MinInt Then Value := Min;
    SetVal(Result, Value);
  End;

Procedure TIntegerPack.Clear;
  Begin
    FList   := nil;
    FResult := 0;
    FResSize := 0;
  End;
und noch'n Beispiel:
Delphi-Quellcode:
Uses Dialogs;

Var P: TIntegerPack;

Begin
  P.Add(1, 13);
  P.Add(0, 5);
  P.Add(-2, 3);
  P.Value[0] := 7;
  P.Value[1] := 3;
  P.Value[2] := 1;
  ShowMessage(Format('%d Bytes > %d Bits > $%.*x',
    [P.Bytes, P.Bits, P.Bytes * 2, P.Result]));

  P.Add(1, 13);
  P.Add(0, 5);
  P.Add(-2, 3);
  P.Result := $0117;
  ShowMessage(Format('%d > %d %d %d',
    [P.Result, P.Value[0], P.Value[1], P.Value[2]]));

silver-moon-2000 15. Mai 2010 21:30

Re: Zwei Werte [0..16] in einem Integer festhalten
 
Ich stelle mir gerade die Frage, ob Ihr alle ein wenig zu kompliziert an die Sache rangegangen seid, oder ob ich es mir vielleicht doch zu leicht mache, aber ich verwende das folgende häufiger:

Zahlen zu einer "kombinieren"
Delphi-Quellcode:
kombinierteZahl := (zahl1 shl 16) + zahl2;
Zahlen wieder trennen
Delphi-Quellcode:
zahl1neu := (kombinierteZahl and FFFF0000) shr 16;
zahl2neu := kombinierteZahl and 0000FFFF;
Ok, zugegeben, damit ist der Zahlenbereich für zahl1 & zahl2 festgelegt auf 2^(SizeOf(Integer)/2), also Word = 65536, aber das sollte doch reichen, wenn man zwei Zahlen <=16 speichern will :stupid:

[edit]
ahh, siehste mal guck: MakeLong und MakeWord kannte ich noch nicht, wieder was gelernt

divBy0 15. Mai 2010 21:53

Re: Zwei Werte [0..16] in einem Integer festhalten
 
Hatte ich doch beschrieben, mit High- und Low-Word. :-D

silver-moon-2000 15. Mai 2010 21:57

Re: Zwei Werte [0..16] in einem Integer festhalten
 
Zitat:

Zitat von divBy0
Hatte ich doch beschrieben, mit High- und Low-Word. :-D

Aargh, sorry, noch ein Posting, das ich überlesen habe.
Scheint so, dass ich bei jedem Lesen des Threads neue Antworten in der Mitte finde, peinlich irgendwie :wall:

himitsu 16. Mai 2010 08:27

Re: Zwei Werte [0..16] in einem Integer festhalten
 
@silver-moon-2000:
Macht ja nix, der TE kennt jetzt das Innere dieser Funktionen
und du hast ja auch gleich noch was gelernt.

Zitat:

Zitat von Jonelmeier
... das soll aber variabel bleiben).
...
Gibt es eine mathematische Lösung für das Problem?

Nun kann er sich variabel eine passende Lösung aussuchen
und verschiedene mathematische und bitverschieberische Lösungen wurden auch genannt.

schöni 17. Mai 2010 08:02

Re: Zwei Werte [0..16] in einem Integer festhalten
 
Zitat:

Zitat von Meflin
Zunächst sucht man nun (durch ausprobieren?) die größte Zahl i (oben dargestellt durch die Funktion q), für die gilt f(i) <= 39. i ist in unserem Fall 8. Dann ist y = 39 - f(8) = 39 - 36 = 3.
x ergibt sich aus i - y = 8 - 3 = 5.

Und so isses auch in wissenschaflichen Fachbüchern erklärt. Da weiß ich aber immer noch nich, die größte Zah wovon.

Was also stellt diese magische Zahl i dar?

Und wofür steht q?

f(i) <= 39 kann zB sein: 39, 38, 37,...1, 0

Aber das sollte ja nun zu Rückberechnung der beiden gespeicherten Zahlen passen? Also bitte noch mal genauer erklären, damit ein unbedarfter das Beispeil auch nachvollziehen kann. Probieren, um die passende Zahl zu finden, reicht mir nicht. Im Extremfall probier ich dann alle zwischen 1 und 37 oder allgemein 1..X durch, was nicht gerade laufzeitfreundlich ist.

Oder ist i immer die Summe der beiden Zahlen.

Was wenn die Summe größer wird als dies Summe aus der Formel?

Meflin 17. Mai 2010 13:11

Re: Zwei Werte [0..16] in einem Integer festhalten
 
Zitat:

Zitat von schöni
Was also stellt diese magische Zahl i dar?

Im Grunde das, was jeder Programmierer darunter versteht: Eine Schleifenvariable ;) Der offizielle Weg besteht darin, bei 0 beginnend f(i) auszurechnen, solange bis f(i) >= h (wobei h das Ergebnis der Paarungsfunktion ist). Das vorletzte (oder letzte im Fall =) Ergebnis bei Abbruch ist dann das gesuchte i.

Zitat:

Und wofür steht q?
Rein mathematisch gedacht bekommst du aus obigem Test eine Menge von Zahlen zurück, die die Bedingung (<= h) erfüllen. q ist die Funktion, die dir aus dieser Menge die Größte zurückgibt. Nicht mehr, aber auch nicht weniger.

Man kann i und damit die beiden Werte auch direkt berechnen:
i = floor(sqrt(2h) - 1/2)

(Online Formeleditor mit Einbindungsfunktion für Webseiten anybody?)


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:55 Uhr.
Seite 2 von 2     12   

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz