2017-01-28 7 views
3

Ich muss einen vorzeichenbehafteten ganzzahligen Wert in/aus einer 64-Bit-Integer-Ganzzahlspalte (BigInt) in SQLite speichern und abrufen. Zur Vereinfachung sei angenommen, dass das Feld die ersten BitCount-Bits des BigInt aufnimmt. Auch übernehmen wir die Bit-Feld in dem Datensatz mit RowID = ändern wollen: rowID zu: Val und beachten Sie, dass die Bits durch das Feld verwendet werden, sind FldBits = (1 < < Bitcount) - 1.Speichern und Abrufen von vorzeichenbehafteten Werten aus einem Bitfeld

Wenn es ein unsigned waren Wert das Speichern und Abrufen sind einfach genug.

// Store 
update BigIntTbl set BigInt = BigInt & ~FldBits | :Val 
where RowID=:RowID; 

// Retrieve 
select BigInt & FldBits 
from BigIntTbl where RowID=:RowID; 

Ich gehe davon aus (aber ich bin keineswegs sicher), dass der beste Weg, um einen signierten Wert zu speichern ist einzustellen: Val die Zweier vor dem Speichern Bits für einen negativen Wert ergänzen. Ich habe die folgende Formel entwickelt, kann aber nicht anders, als zu fühlen, dass ich es mir selbst schwer mache.

// Store 
update BigIntTbl set BigInt = BigInt & ~FldBits | 
(:Val + (:Val<0) * (1 << BitCount)) 
// above sets :Val to 2s complement bit pattern for -ve values and leaves +ve values unchanged 

// Retreive 
select (BigInt & FldBits) - 2 * (BigInt & (1 << (BitCount-1))) 
from BigIntTbl where RowID=:RowID; 

Ich dachte über nur ein Offset (das heißt hinzufügen Offset beim Speichern, zieht Offset beim Abrufen) Anwendung aber aus Gründen, die ich nicht in gehen, ich will Null als Null gespeichert werden. Der Klarheit halber wird angenommen, dass das Vorzeichenbit (Bit 63) in BigInt niemals verwendet wird.

Fragen:

  1. Kann ich (:Val + (:Val<0) * (1 << BitCount)) mit (:Val & FldBits)

  2. Alles ersetzen einfacher als (BigInt & FldBits) - 2 * (BigInt & (1 << (BitCount-1))) zum Abruf?

+1

Wiederholen Sie die Tabelle, um separate Daten in separaten Feldern abzulegen. Dafür gibt es Datenbanken. – stark

+0

Warum möchten Sie Bit-Operationen in einer Datenbank ausführen? Ich würde die Datenbank nur zum Speichern der Rohdaten verwenden, wenn Sie Bit-Operationen für sie ausführen, sie aus der Datenbank holen und dann die Operation ausführen möchten. – Alex

+0

LOL stark. Ich bin heute nicht an die Stelle gekommen, wo ich heute bin, indem ich getrennte Daten in getrennte Felder setze. Im Ernst, ein gepackter Schlüssel kann Lesevorgänge beschleunigen. – NoComprende

Antwort

0

SOLUTION (hoffe ich)

Nehmen Sie den allgemeinen Fall eines 64-Bit-Ganzzahl mit Vorzeichen BigInt und betrachten ein Bitfeld unterzeichnet, die bei Bit Lobit beginnt (0-basiert) und nimmt Bitcount Bits.

FldBits = ((1 << BitCount) - 1) << LoBit; 

können Sie speichern eine beliebige Anzahl Val zwischen - (1 < < (Bitcount - 1)) und (1 < < (Bitcount - 1)) - 1 mit

BigInt = BigInt & ~FldBits | (Val << LoBit & FldBits) 

und laden diese mit

Val = (BigInt & FldBits) << (64 - BitCount - LoBit) >> (64 - BitCount); 

Ein einfaches SQL-Beispiel

select (?1 & 31) <<59>> 59; 

Jeder Wert zwischen -16 und 15 für? 1 wird 1 zurückgeben (vergleichen Sie mit 'wählen? 1 & 31').

Die Zweiwegeverschiebung führt dazu, dass das obere Bit des Bitfelds in allen höheren Bits repliziert wird. Wenn Val eine + ve Nummer ist, bedeutet das, dass es mit Nullen aufgefüllt ist. Wenn Val -ve ist, wird es mit Einsen aufgefüllt, was zu der 64-Bit-Ganzzahl führt, die die 64-Bit-Repräsentation von Val enthält.

Verwandte Themen