In C, wie berechne ich die vorzeichenbehaftete Differenz zwischen zwei vorzeichenlosen 48-Bit-Ganzzahlen?

8

Ich habe zwei Werte von einem unsignierten 48-Bit-Nanosekunden-Zähler, der sich umschließen lässt.

Ich brauche den Unterschied der beiden Zeiten in Nanosekunden.

Ich denke, ich kann davon ausgehen, dass die Lesungen ungefähr zur gleichen Zeit gemacht wurden, also von den zwei möglichen Antworten denke ich, dass ich sicher bin, die kleinsten zu nehmen.

Sie werden beide als uint64_t gespeichert. Weil ich glaube nicht, dass ich 48-Bit-Typen haben kann.

Ich möchte den Unterschied zwischen ihnen berechnen, als eine vorzeichenbehaftete Ganzzahl (vermutlich int64_t ), die für das Wrapping verantwortlich ist.

so z.B. wenn ich mit

anfange %Vor%

Das Ergebnis von x-y ist 2 und bleibt auch erhalten, wenn ich sowohl x als auch y inkrementiere, auch wenn sie den oberen Wert des maximalen Wertes 0xffffffffffff

überschreiten

Ähnlich, wenn x = 3, y = 5, dann ist x-y gleich -2 und bleibt so, wenn x und y gleichzeitig inkrementiert werden.

Wenn ich x , y als uint48_t und die Differenz als int48_t deklarieren könnte, dann denke ich

%Vor%

würde einfach funktionieren.

Wie simuliere ich dieses Verhalten mit der 64-Bit-Arithmetik, die ich zur Verfügung habe?

(Ich denke, dass jeder Computer, auf dem dieser wahrscheinlich läuft, die Zweierkomplementarithmetik verwendet)

P.S. Ich kann das vielleicht aushacken, aber ich frage mich, ob es eine nette, ordentliche Art und Weise gibt, so etwas zu tun, was die nächste Person, die meinen Code liest, verstehen kann.

P.P.S Außerdem wird dieser Code in den engsten engen Schleifen enden, also wäre etwas, das effizient kompiliert werden würde, schön, so dass, wenn es eine Wahl gibt, die Geschwindigkeit die Lesbarkeit übertrifft.

    
John Lawrence Aspden 24.05.2017, 19:10
quelle

3 Antworten

5

Sie können einen 48-Bit-Integer-Typ ohne Vorzeichen simulieren, indem Sie nur die obersten 16 Bits eines uint64_t nach einer arithmetischen Operation maskieren. Um zum Beispiel den Unterschied zwischen diesen beiden Zeiten zu machen, könnten Sie Folgendes tun:

%Vor%

Sie erhalten den richtigen Wert auch dann, wenn der Zähler während des Vorgangs umläuft. Wenn der Zähler nicht umgeht, ist die Maskierung nicht erforderlich, aber auch nicht schädlich.

Wenn Sie möchten, dass dieser Unterschied von Ihrem Compiler als vorzeichenbehaftete Ganzzahl erkannt wird, müssen Sie sign extend das 48. Bit. Das heißt, wenn das 48. Bit gesetzt ist, ist die Zahl negativ, und Sie möchten das 49ste durch das 64. Bit Ihrer 64-Bit-Ganzzahl setzen. Ich denke, ein einfacher Weg das zu tun ist:

%Vor%

Warnung: Sie sollten dies wahrscheinlich testen, um sicherzustellen, dass es funktioniert, und auch darauf achten, dass es ein implementierungsdefiniertes Verhalten gibt, wenn ich uint64_t auf int64_t umsetze, und ich denke, dass dies der Fall ist implementierungsdefiniertes Verhalten, wenn ich eine negative Zahl mit Vorzeichen nach rechts verschiebe. Ich bin mir sicher, dass ein C-Anwalt etwas mit etwas robusterem anfangen könnte.

Update: Das OP weist darauf hin, dass, wenn Sie die Operation der Differenzbildung und Zeichenerweiterung kombinieren, keine Maskierung erforderlich ist. Das würde so aussehen:

%Vor%     
David Grayson 24.05.2017, 19:36
quelle
3
%Vor%

Hier verwenden wir nur die explizite Breite des Felds als 48 Bit und mit diesem (zugegebenermaßen etwas peinlichen) Typ leben Sie es mit Ihrem Compiler, um verschiedene Architekturen / Plattformen / was nicht zu behandeln.

Wie folgt:

%Vor%

Natürlich können Sie in der letzten Anweisung die Restoperation mit % (overflow.u48 + 1) durchführen, wenn Sie das bevorzugen.

    
YePhIcK 24.05.2017 20:06
quelle
2

Weißt du, was früher gelesen wurde und was später war? Wenn ja:

%Vor%

wo WRAPVAL ist (1 << 48) ist ziemlich einfach zu lesen.

    
mtrw 24.05.2017 19:16
quelle

Tags und Links