![]() |
AW: Bit-Schiebereien
Um wieviele Bit wird denn verschoben?
Bei maximal 8 und verschieben nacht rechts: - man nimmt ein Byte und verschiebt dessen Bits um X nach rechts - dazu kommen noch die Bits des vorherrigen Bytes, welche um (8-X) Bits nach links verschoben werden - das Beides dann mit OR verbinden - und nun nur noch das Ganze für jedes andere Byte machen (vom rechten Byte, bis zum Linken) Das läßt sich natürlich noch bis Integer/Int64 aufweiten, wobei man da auf "ungerade" Bytes achten muß, welche keine vollen Interger/Int64 ergeben. |
AW: Bit-Schiebereien
Zitat:
|
AW: Bit-Schiebereien
Wie wäre es mit einer kleinen Klasse?
Delphi-Quellcode:
Und 'GetBits' macht nichts anderes, als die Bytes aus data von Index BitsFrom/8-BitsTo/8 zu kopieren und um BitsFrom mod 8 zu shiften (den Überlauf vom folgenden Byte einmaskieren), und vom letzten Byte müssen die Bits (BitsTo mod 8 - BitsFrom mod 8) weggeschnippelt werden.
Type
TBits = Class public constructor Create (data : TBytes); function GetBits (BitFrom, BitTo : Integer) : TBytes; End; Irgendwie so jedenfalls. Mit Papier und Stift sind die Shiftoffsets und das letzte Maskieren doch schnell zusammengezählt. Alternativ (aber saulangsam) überführt man den Byte-Stream in ein Array of Boolean und bei der Abfrage erzeugt man aus dem Bits dann wieder einen Byte-Stream. |
AW: Bit-Schiebereien
Zitat:
Die praktische Umsetzung ist der zweite Schritt. Gruß K-H |
AW: Bit-Schiebereien
Und wenn man groß hinaus will:
Es gibt unzählige Mathebibliotheken für "große" Zahlen, welche man auch verwenden könnte. |
AW: Bit-Schiebereien
Wie schnell muss dass denn sein?
Ich frage einen 4-Bit Wert aus 2 Bytes
Code:
genau 1.000.000 ab und das dauert hier so 18ms.
1111111001111111
Wenn das schnell genug ist, dann kann ich den Code hier mal reinstellen. |
AW: Bit-Schiebereien
Zitat:
Gruß K-H |
AW: Bit-Schiebereien
Ok, hier der Code.
Durch das Verschieben sollten keine Wert mit mehr als 25bit abgerufen werden, da es sonst zu komischen Ergebnissen kommen kann :) Es erfolgt keine Überprüfung der Index-Werte ... wer das möchte, der kann sich das ja noch einbauen :) UPDATE Ich habe nochmals ca. 2ms weniger (bei 1.000.000 Zugriffen) herausgekitzelt durch eine Änderung in der
Delphi-Quellcode:
Methode :)
GetData
Delphi-Quellcode:
program dp_180297;
{$APPTYPE CONSOLE} {$R *.res} uses System.Generics.Collections, System.Classes, System.SysUtils, System.Diagnostics, BaseData in 'BaseData.pas', BaseDataFactory in 'BaseDataFactory.pas'; type TData1 = class( TBaseData ) public property Value1 : Integer index $000604 read GetData; // Offset 6 Bit-Width 4 property Value2 : Integer index $000010 read GetData; // Offset 0 Bit-Width 16 end; procedure ValueCheck( AInstance : TData1 ); begin Assert( AInstance.Value1 = 9 ); Assert( AInstance.Value2 = 65151 ); end; procedure PerformanceCheck( AInstance : TData1 ); const C_ROUNDS = 1000000; var LWatch : TStopwatch; LValue : Integer; LIdx : Integer; begin LWatch := TStopwatch.StartNew; for LIdx := 1 to C_ROUNDS do begin LValue := AInstance.Value1; end; LWatch.Stop; Writeln( C_ROUNDS, ' Rounds in ', LWatch.ElapsedMilliseconds, 'ms' ); end; procedure FactoryTest; var LStream : TStream; LData : TBytes; LInstance : TBaseData; begin TBaseDataFactory.RegisterType( $00, TData1 ); LStream := TMemoryStream.Create; try LData := TBytes.Create( $00 { Type } , $02 { Size of Data } , $FE, $7F ); LStream.Write( LData, Length( LData ) ); LStream.Seek( 0, soFromBeginning ); LInstance := TBaseDataFactory.CreateFromStream( LStream ); try ValueCheck( LInstance as TData1 ); finally LInstance.Free; end; finally LStream.Free; end; end; procedure Main; var LData : TBytes; LInstance : TData1; begin LData := TBytes.Create( $FE, $7F ); // 1111111001111111 // ......====...... // Value1 ^ = 1001(bin) = 9(decimal) LInstance := TData1.Create( LData ); try ValueCheck( LInstance ); PerformanceCheck( LInstance ); finally LInstance.Free; end; end; begin ReportMemoryLeaksOnShutdown := True; try Main; FactoryTest; except on E : Exception do Writeln( E.ClassName, ': ', E.Message ); end; ReadLn; end.
Delphi-Quellcode:
unit BaseData;
interface uses System.SysUtils; type TBaseData = class private FData : TBytes; protected function GetData( const Index : integer ) : integer; public constructor Create( AData : TBytes ); end; implementation { TBaseData } constructor TBaseData.Create( AData : TBytes ); begin inherited Create; FData := AData; end; function TBaseData.GetData( const Index : integer ) : integer; var LBitCount : integer; LBitOffset : integer; LByteOffset : integer; LByteIdx : PByte; LMask : Byte; begin LBitCount := index and $FF; LBitOffset := ( index shr 8 ) and $FFFF; LByteOffset := LBitOffset div 8; LBitOffset := LBitOffset - LByteOffset * 8; LByteIdx := @FData[LByteOffset]; LMask := ( 1 shl ( 8 - LBitOffset ) ) - 1; Result := ( LByteIdx^ and LMask ); LBitCount := LBitCount - ( 8 - LBitOffset ); while LBitCount > 0 do begin Inc( LByteIdx ); Result := Result shl 8; Result := Result or LByteIdx^; LBitCount := LBitCount - 8; end; if LBitCount < 0 then Result := Result shr ( -LBitCount ); end; end.
Delphi-Quellcode:
unit BaseDataFactory;
interface uses System.Generics.Collections, System.Classes, System.SysUtils, BaseData; type TBaseDataClass = class of TBaseData; TBaseDataFactory = class private class var _Types : TDictionary<Byte, TBaseDataClass>; protected class constructor Create; class destructor Destroy; public class function CreateFromStream( AStream : TStream ) : TBaseData; class procedure RegisterType( AType : Byte; AClass : TBaseDataClass ); end; implementation { TBaseDataFactory } class constructor TBaseDataFactory.Create; begin _Types := TDictionary<Byte, TBaseDataClass>.Create; end; class function TBaseDataFactory.CreateFromStream( AStream : TStream ) : TBaseData; var LType : Byte; LSize : Byte; LData : TBytes; LClass : TBaseDataClass; begin AStream.Read( LType, SizeOf( LType ) ); AStream.Read( LSize, SizeOf( LSize ) ); SetLength( LData, LSize ); AStream.Read( LData, LSize ); LClass := _Types[LType]; // Bei einem unbekannten Typen wird hier eine Exception geworfen Result := LClass.Create( LData ); end; class destructor TBaseDataFactory.Destroy; begin _Types.Free; end; class procedure TBaseDataFactory.RegisterType( AType : Byte; AClass : TBaseDataClass ); begin _Types.AddOrSetValue( AType, AClass ); end; end. |
AW: Bit-Schiebereien
!Danke!:-D
K-H |
AW: Bit-Schiebereien
Zitat:
Ein kleines Performance-Update habe ich auch noch eingebaut :) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:02 Uhr. |
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 by Thomas Breitkreuz