簡體   English   中英

將兩個不同位長的大整數可逆地編碼為一個整數

[英]Reversibly encode two large integers of different bit lengths into one integer

我想將兩個最大位長可能不同的大整數編碼為一個整數。 第一個整數是有符號的(可以是負數),而第二個是無符號的(總是非負數)。 如果位長分別為mn ,則返回整數的位長應小於或等於m + n

只有n (但不是m )是預先知道的並且是固定的。 作為示例,該解決方案將用於將 61 位以上的有符號納秒時間戳與 256 位無符號隨機性結合起來,以形成一個有符號 317 位以上的唯一標識符。

我正在使用最新的 Python。 m == n特殊情況下,有一個相關的預先存在的問題解決了這個問題。

由於n是固定的,所以問題很簡單:將 ( a , b ) 編碼為a •2 n + b

如果mn不固定,則問題是不可能的,因為它要求我們將(兩位a ,一位b )和(一位a ,兩位b )都編碼為三位,這意味着我們必須編碼十二種可能性 (0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3) ), (2, 0), (2, 1), (3, 0), (3, 1) 三種比特的八種組合,這是不可能的。

該解決方案使用基本的位移位和位提取。 使用位運算應該比使用更高級別的運算(例如求冪和乘法)更快。

基本解決方案與特殊情況下的解決方案大致相同,因為在任何一種情況下都只需要一個整數的最大位長度。 然而,測試並非如此。

from typing import Tuple
import unittest


class IntMerger:
    """Reversibly encode two integers into a single integer.

    Only the first integer can be signed (possibly negative). The second
    integer must be unsigned (always non-negative).

    In the merged integer, the left bits are of the first input integer, and
    the right bits are of the second input integer.
    """
    # Ref: https://stackoverflow.com/a/54164324/
    def __init__(self, num_bits_int2: int):
        """
        :param num_bits_int2: Max bit length of second integer.
        """
        self._num_bits_int2: int = num_bits_int2
        self._max_int2: int = self._max_int(self._num_bits_int2)

    @staticmethod
    def _max_int(num_bits: int) -> int:
        return (1 << num_bits) - 1

    def merge(self, int1: int, int2: int) -> int:
        return (int1 << self._num_bits_int2) | int2

    def split(self, int12: int) -> Tuple[int, int]:
        int1 = int12 >> self._num_bits_int2
        int2 = int12 & self._max_int2
        return int1, int2


class TestIntMerger(unittest.TestCase):
    def test_intmerger(self):
        max_num_bits = 8
        for num_bits_int1 in range(max_num_bits + 1):
            for num_bits_int2 in range(max_num_bits + 1):
                expected_merged_max_num_bits = num_bits_int1 + num_bits_int2
                merger = IntMerger(num_bits_int2)
                maxint1 = (+1 << num_bits_int1) - 1
                minint1 = (-1 << num_bits_int1) + 1
                for int1 in range(minint1, maxint1 + 1):
                    for int2 in range(1 << num_bits_int2):
                        int12 = merger.merge(int1, int2)
                        # print(f'{int1} ({num_bits_int1}b), {int2} ({num_bits_int2}b) = {int12} ({int12.bit_length()}b)')
                        self.assertLessEqual(int12.bit_length(), expected_merged_max_num_bits)
                        self.assertEqual((int1, int2), merger.split(int12))
                self.assertEqual(int12.bit_length(), expected_merged_max_num_bits)


if __name__ == '__main__':
    unittest.main()

用法示例:

>>> merger = IntMerger(12)

>>> merger.merge(13, 8)
53256
>>> merger.split(_)
(13, 8)

>>> merger.merge(-13, 8)
-53240
>>> merger.split(_)
(-13, 8)

如果您絕對必須具有完全可逆性,則需要放寬至少一個隱含的初始條件(因為如果您不單獨記住這些數字中的任何一個並且響應位長 R 小於 m+n,則您將不可撤銷地失去完全可逆性):

  • 要么你應該讓 R 完全等於 m+n,在這種情況下,最簡單的方法是將 m 長度左移 n 位,然后添加 n 位數字(反轉,復制,右移由 n 位得到 m 長度的 1,左移 n 位並從/與編碼數減去/按位異或得到 n 長度的數),
  • 或者你應該在某處/以某種方式單獨記住其中一個數字(希望它對用戶來說很常見?)並且只是按位異或數字(反轉,只是按位異或結果與存儲的數字); 獎勵積分,如果這對用戶來說很常見,那么每個用戶超過第一個的任何額外編碼 ID 只會增加 max(m,n) 位數據到存儲需求。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM