Отображение двух целых в одно уникальным и детерминированным способом

235

Представьте два положительных целых числа A и B. Я хочу объединить эти два в одно целое число C.

Не может быть других целых чисел D и E, которые объединяются в C. Поэтому объединение их с помощью оператора сложения не работает. Например, 30 + 10 = 40 = 40 + 0 = 39 + 1 Не работает конкатенация. Например, «31» + «2» = 312 = «3» + «12»

Эта комбинированная операция также должна быть детерминированной (всегда давать один и тот же результат с одними и теми же входными данными) и всегда должна давать целое число с положительной или отрицательной стороны целых чисел.

вред
источник
10
Вы должны уточнить, имеете ли вы в виду целые числа в программном обеспечении или целые числа в математике. В программном обеспечении вы выбираете любой целочисленный тип, и он будет иметь размер, поэтому у вас есть их конечное число, поэтому решения не существует (если, конечно, ваши входные данные гарантированно не окажутся в некотором диапазоне, а ваши выходные данные могут быть любое целое число). В математике см. Решение ASK.
Даниэль Даранас
Я говорю о ограниченных целых числах в низком положительном диапазоне. Скажите от 0 до 10000
вред
27
@harm: А как насчет просто 10,001*A + B?
BlueRaja - Дэнни Пфлюгофт
2
Я нашел эти функции PHP: gist.github.com/hannesl/8031402
cakan
Если порядок не имеет значения, например: (3,12) и (12,3) дают тот же результат, я использую «A + B» + «A * B»
Содж

Ответы:

233

Вы ищете биективное NxN -> Nотображение. Они используются, например, для ласточкиного хвоста . Посмотрите этот PDF для ознакомления с так называемыми функциями сопряжения . Википедия представляет особую функцию сопряжения, а именно функцию сопряжения Кантора :

pi (k1, k2) = 1/2 (k1 + k2) (k1 + k2 + 1) + k2

Три замечания:

  • Как ясно дали понять другие, если вы планируете реализовать функцию сопряжения, вскоре вы можете обнаружить, что вам нужны сколь угодно большие целые числа (bignums).
  • Если вы не хотите проводить различие между парами (a, b) и (b, a), то отсортируйте a и b перед применением функции сопряжения.
  • На самом деле я солгал. Вы ищете биективное ZxZ -> Nотображение. Функция Кантора работает только на неотрицательных числах. Однако это не проблема, потому что легко определить биекцию f : Z -> N, например так:
    • f (n) = n * 2, если n> = 0
    • f (n) = -n * 2 - 1, если n <0
Stephan202
источник
13
+1 Я думаю, что это правильный ответ для неограниченных целых чисел.
Неизвестно
4
Как я могу получить снова значение k1, k2?
MinuMaster
3
@MinuMaster: это описано в той же статье в Википедии, в разделе Инвертирование функции сопряжения Кантора .
Stephan202
4
Смотрите также функцию Шудзика, объясненную newfal ниже.
OliJG
1
Хотя это верно для неограниченных целых чисел, это не лучше для ограниченных целых чисел. Я думаю, что комментарий @ blue-raja имеет больше смысла.
Кардасис
226

Функция сопряжения Кантора действительно одна из лучших, учитывая ее простоту, скорость и эффективность использования пространства, но кое-что еще лучше опубликовано в Wolfram Мэтью Шудзиком, здесь . Ограничение функции сопряжения Кантора (относительно) состоит в том, что диапазон закодированных результатов не всегда остается в пределах 2Nбитового целого числа, если входные данные являются Nдвухбитными целыми числами. То есть, если мои входные данные представляют собой 16двухбитные целые числа в диапазоне от 0 to 2^16 -1, то 2^16 * (2^16 -1)возможны комбинации входных данных, поэтому, в соответствии с очевидным принципом Pigeonhole , нам нужен выход по крайней мере такого размера 2^16 * (2^16 -1), который равен 2^32 - 2^16или, другими словами, карте32битовые числа должны быть выполнимыми в идеале. Это не может иметь мало практического значения в мире программирования.

Функция сопряжения Кантора :

(a + b) * (a + b + 1) / 2 + a; where a, b >= 0

Отображение для двух максимально 16-битных целых чисел (65535, 65535) будет 8589803520, которое, как вы видите, не может быть вписано в 32 бита.

Введите функцию Шудзика :

a >= b ? a * a + a + b : a + b * b;  where a, b >= 0

Отображение для (65535, 65535) теперь будет 4294967295, которое, как вы видите, является 32-битным (от 0 до 2 ^ 32 -1) целым числом. Вот где это решение идеально, оно просто использует каждую точку в этом пространстве, поэтому ничто не может быть более эффективным.


Теперь, учитывая тот факт, что мы обычно имеем дело со знаковыми реализациями чисел различных размеров в языках / инфраструктурах, давайте рассмотрим signed 16битовые целые числа, начиная от -(2^15) to 2^15 -1(позже мы увидим, как расширить даже выходной поток, чтобы охватить диапазон со знаком). Так как aи bдолжны быть положительными, они варьируются от 0 to 2^15 - 1.

Функция сопряжения Кантора :

Отображение для двух максимальных 16-разрядных целых чисел со знаком (32767, 32767) будет 2147418112, что немного меньше максимального значения для 32-разрядного целого числа со знаком.

Теперь функция Шудзика :

(32767, 32767) => 1073741823, намного меньше ..

Давайте учтем отрицательные целые числа. Это выходит за рамки первоначального вопроса, который я знаю, но просто помогаю будущим посетителям.

Функция сопряжения Кантора :

A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
(A + B) * (A + B + 1) / 2 + A;

(-32768, -32768) => 8589803520, то есть Int64. 64-битный выход для 16-битных входов может быть таким непростительным !!

Функция Шудзика :

A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
A >= B ? A * A + A + B : A + B * B;

(-32768, -32768) => 4294967295, который является 32-битным для диапазона без знака или 64-битным для диапазона со знаком, но все же лучше.

Теперь все это пока результат всегда был положительным. В мире со знаком будет еще больше экономии места, если мы сможем перевести половину вывода на отрицательную ось . Вы можете сделать это так для Шудзика:

A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
C = (A >= B ? A * A + A + B : A + B * B) / 2;
a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;

(-32768, 32767) => -2147483648

(32767, -32768) => -2147450880

(0, 0) => 0 

(32767, 32767) => 2147418112

(-32768, -32768) => 2147483647

Что я делаю: применив вес 2к входам и пройдя через функцию, затем разделю выходной сигнал на два и перенесу некоторые из них на отрицательную ось, умножив на -1.

См. Результаты, для любого ввода в диапазоне числа 16битов со знаком, выход лежит в пределах 32целого числа битов со знаком, что здорово. Я не уверен, как сделать то же самое для функции сопряжения Кантора, но не пытался так сильно, как это не так эффективно. Кроме того, чем больше вычислений, связанных с функцией сопряжения Кантора, тем медленнее и ее .

Вот реализация C #.

public static long PerfectlyHashThem(int a, int b)
{
    var A = (ulong)(a >= 0 ? 2 * (long)a : -2 * (long)a - 1);
    var B = (ulong)(b >= 0 ? 2 * (long)b : -2 * (long)b - 1);
    var C = (long)((A >= B ? A * A + A + B : A + B * B) / 2);
    return a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
}

public static int PerfectlyHashThem(short a, short b)
{
    var A = (uint)(a >= 0 ? 2 * a : -2 * a - 1);
    var B = (uint)(b >= 0 ? 2 * b : -2 * b - 1);
    var C = (int)((A >= B ? A * A + A + B : A + B * B) / 2);
    return a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
}

Поскольку промежуточные вычисления могут превышать пределы 2Nцелого числа со знаком, я использовал 4Nцелочисленный тип (последнее деление на 2возвращает результат в 2N).

Ссылка, которую я предоставил на альтернативное решение, хорошо изображает график функции, использующей каждую точку в пространстве. Удивительно видеть, что вы можете уникально закодировать пару координат в одно число обратимо! Волшебный мир чисел !!

Навфал
источник
5
Что будет модифицированной unhash-функцией для целых чисел со знаком?
Арец Пэглис
7
Этот ответ смущает меня. Если вы хотите отобразить (0,0)через (65535,65535)к одному числу, то a<<16 + bлучше в основном во всех отношениях (быстрее, проще, легче понять, что более очевидно) . Если вы хотите , (-32768,-32768)чтобы (327687,327687)вместо этого, только при условии 32768 первыми.
BlueRaja - Дэнни Пфлугхофт
2
@ BlueRaja-DannyPflughoeft ты прав. Мой ответ будет действительным, если диапазон не ограничен или неизвестен. Я обновлю это. Я написал это прежде, чем предел имел значение для меня. Редактирование этого ответа давно было в моей голове. Я найду время в ближайшее время.
Nawfal
Работает ли функция Шудзика для комбинаций или перестановок. Вроде бы перестановки не так ли? Если я хочу использовать для комбинации, могу ли я просто исключить части алгоритма IF и Else?
Джейми Маршалл
Вот реализация Python функции Шудзика, обобщенной на кортежи любой длины: gitlab.com/snippets/32559
Доктор J
47

Если A и B могут быть выражены 2 байтами, вы можете объединить их в 4 байта. Поместите A в самую значительную половину, а B в самую младшую.

В языке C это дает (при условии, что sizeof (short) = 2 и sizeof (int) = 4):

int combine(short A, short B)
{
    return A<<16 | B;
}

short getA(int C)
{
    return C>>16;
}

short getB(int C)
{
    return C & 0xFFFF;
}
mouviciel
источник
3
combine()следует return (unsigned short)(A<<16) | (unsigned short)(B); так , что отрицательные числа могут быть упакованы надлежащим образом .
Энди
2
@ Энди A<<16выйдет за пределы. Это должно бытьreturn (unsigned int)(A<<16) | (unsigned short)(B);
DanSkeel
15

Это вообще возможно?
Вы объединяете два целых числа. Оба имеют диапазон от -2 147 483 648 до 2 147 483 647, но вы будете принимать только положительные результаты. Это составляет 2147483647 ^ 2 = 461169E + 18 комбинаций. Поскольку каждая комбинация должна быть уникальной И приводить к целому числу, вам понадобится какое-то магическое целое число, которое может содержать это количество чисел.

Или моя логика ошибочна?

Борис Калленс
источник
+1 Я тоже так думаю (хотя я сделал расчет, говоря, что порядок A и B не имеет значения)
lc.
4
Да, ваша логика верна по принципу голубя. К сожалению, спрашивающий не уточнил, является ли целое число ограниченным или нет.
неизвестно
Да, у меня тоже была эта запоздалая мысль, но я думал, что сообщение по сути то же самое, поэтому я не стал вспоминать.
Борис Калленс
Кроме того, я только что понял, что должен снова забрать учебники для расчета шансов (буквальный перевод с голландского).
Борис Калленс
2
@Boris: Kansrekening - это «теория вероятностей».
Stephan202
8

Стандартный математический способ для натуральных чисел состоит в использовании уникальности простой факторизации.

f( x, y ) -> 2^x * 3^y

Недостатком является то, что изображение имеет тенденцию охватывать довольно большой диапазон целых чисел, поэтому, когда дело доходит до выражения отображения в компьютерном алгоритме, у вас могут возникнуть проблемы с выбором подходящего типа для результата.

Вы можете изменить это, чтобы иметь дело с отрицательным xи yкодируя флаги со степенями 5 и 7 членов.

например

f( x, y ) -> 2^|x| * 3^|y| * 5^(x<0) * 7^(y<0)
CB Bailey
источник
Математика в порядке. Но, как говорит Борис, если вы хотите запустить это как компьютерную программу, вы должны принять во внимание конечность машины. Алгоритм будет работать правильно для подмножества целых чисел, представленных на соответствующем компьютере.
Ювал Ф
2
Я утверждал это во втором абзаце. Теги в вопросе обозначают «алгоритм», «математический» и «детерминированный», а не какой-либо конкретный язык. Диапазон ввода не может быть ограничен, и среда может иметь неограниченный целочисленный тип «bigint».
CB Bailey
8

Пусть число aбудет первым, bвторым. Позвольте pбыть a+1-th простое число, qбудет b+1-th простое число

Тогда результат pq, если a<b,или 2pqесли a>b. Если a=bда, то будет p^2.

Просить
источник
4
Я сомневаюсь, что вы хотели бы решение NP.
user44242
1
Разве это не дает одинаковый результат для a = 5, b = 14 и a = 6, b = 15?
Ливен Керсмакерс
3
Два произведения двух разных простых чисел не могут иметь одинаковый результат (разложение по уникальному первичному фактору) a = 5, b = 14 -> результат равен 13 * 47 = 611 a = 6, b = 15 -> результат равен 17 * 53 = 901
спросите
4

Не так сложно построить отображение:

   1 2 3 4 5 используйте это отображение, если (a, b)! = (B, a)
1 0 1 3 6 10
2 2 4 7 11 16
3 5 8 12 17 23
4 9 13 18 24 31
5 14 19 25 32 40

   1 2 3 4 5 используйте это отображение, если (a, b) == (b, a) (зеркало)
1 0 1 2 4 6
2 1 3 5 7 10
3 2 5 8 11 14
4 4 8 11 15 19
5 6 10 14 19 24


    0 1 -1 2 -2 используйте это, если вам нужен отрицательный / положительный
 0 0 1 2 4 6
 1 1 3 5 7 10
-1 2 5 8 11 14
 2 4 8 11 15 19
-2 6 10 14 19 24

Выяснить, как получить значение для произвольного a, b немного сложнее.

дельфин
источник
4

f(a, b) = s(a+b) + a, где s(n) = n*(n+1)/2

  • Это функция - она ​​детерминированная.
  • Это также инъективно - f отображает разные значения для разных (a, b) пар. Вы можете доказать это, используя факт s(a+b+1)-s(a+b) = a+b+1 < a.
  • Он возвращает довольно маленькие значения - хорошо, если вы собираетесь использовать его для индексации массива, так как массив не должен быть большим.
  • Это удобно для кэша - если две (a, b) пары близки друг к другу, то f отображает числа, которые близки друг к другу (по сравнению с другими методами).

Я не понял, что Вы подразумеваете под:

должен всегда давать целое число на положительной или отрицательной стороне целых чисел

Как я могу написать (больше чем), (меньше чем) символы на этом форуме?

libeako
источник
2
Больше чем и меньше чем символы должны хорошо работать в backtick escapes.
TRiG
Это эквивалентно функции сопряжения Кантора, и поэтому не работает с отрицательными целыми числами.
Давор Йосипович
4

Хотя ответ Stephan202 является единственным действительно общим, для целых чисел в ограниченном диапазоне вы можете добиться большего успеха. Например, если ваш диапазон составляет 0,10 000, то вы можете сделать:

#define RANGE_MIN 0
#define RANGE_MAX 10000

unsigned int merge(unsigned int x, unsigned int y)
{
    return (x * (RANGE_MAX - RANGE_MIN + 1)) + y;
}

void split(unsigned int v, unsigned int &x, unsigned int &y)
{
    x = RANGE_MIN + (v / (RANGE_MAX - RANGE_MIN + 1));
    y = RANGE_MIN + (v % (RANGE_MAX - RANGE_MIN + 1));
}

Результаты могут помещаться в одно целое число в диапазоне до квадратного корня из числа целочисленных типов. Это упаковывает немного более эффективно, чем более общий метод Stephan202. Также значительно проще декодировать; не требующий квадратных корней, для начала :)

bdonlan
источник
Это случайно возможно для поплавков?
Лукас
4

Для положительных целых чисел в качестве аргументов и там, где порядок аргументов не имеет значения:

  1. Вот неупорядоченная функция сопряжения :

    <x, y> = x * y + trunc((|x - y| - 1)^2 / 4) = <y, x>
    
  2. Для x ≠ y вот уникальная неупорядоченная функция сопряжения :

    <x, y> = if x < y:
               x * (y - 1) + trunc((y - x - 2)^2 / 4)
             if x > y:
               (x - 1) * y + trunc((x - y - 2)^2 / 4)
           = <y, x>
    
ma11hew28
источник
3

Проверьте это: http://en.wikipedia.org/wiki/Pigeonhole_principle . Если A, B и C одного типа, это невозможно сделать. Если A и B являются 16-разрядными целыми числами, а C - 32-разрядными, то вы можете просто использовать сдвиг.

Сама природа алгоритмов хеширования заключается в том, что они не могут предоставить уникальный хеш для каждого отдельного ввода.

Гру
источник
2

Вот расширение кода @DoctorJ на неограниченные целые числа, основанное на методе, заданном @nawfal. Он может кодировать и декодировать. Он работает с обычными массивами и массивами numpy.

#!/usr/bin/env python
from numbers import Integral    

def tuple_to_int(tup):
    """:Return: the unique non-negative integer encoding of a tuple of non-negative integers."""
    if len(tup) == 0:  # normally do if not tup, but doesn't work with np
        raise ValueError('Cannot encode empty tuple')
    if len(tup) == 1:
        x = tup[0]
        if not isinstance(x, Integral):
            raise ValueError('Can only encode integers')
        return x
    elif len(tup) == 2:
        # print("len=2")
        x, y = tuple_to_int(tup[0:1]), tuple_to_int(tup[1:2])  # Just to validate x and y

        X = 2 * x if x >= 0 else -2 * x - 1  # map x to positive integers
        Y = 2 * y if y >= 0 else -2 * y - 1  # map y to positive integers
        Z = (X * X + X + Y) if X >= Y else (X + Y * Y)  # encode

        # Map evens onto positives
        if (x >= 0 and y >= 0):
            return Z // 2
        elif (x < 0 and y >= 0 and X >= Y):
            return Z // 2
        elif (x < 0 and y < 0 and X < Y):
            return Z // 2
        # Map odds onto negative
        else:
            return (-Z - 1) // 2
    else:
        return tuple_to_int((tuple_to_int(tup[:2]),) + tuple(tup[2:]))  # ***speed up tuple(tup[2:])?***


def int_to_tuple(num, size=2):
    """:Return: the unique tuple of length `size` that encodes to `num`."""
    if not isinstance(num, Integral):
        raise ValueError('Can only encode integers (got {})'.format(num))
    if not isinstance(size, Integral) or size < 1:
        raise ValueError('Tuple is the wrong size ({})'.format(size))
    if size == 1:
        return (num,)
    elif size == 2:

        # Mapping onto positive integers
        Z = -2 * num - 1 if num < 0 else 2 * num

        # Reversing Pairing
        s = isqrt(Z)
        if Z - s * s < s:
            X, Y = Z - s * s, s
        else:
            X, Y = s, Z - s * s - s

        # Undoing mappint to positive integers
        x = (X + 1) // -2 if X % 2 else X // 2  # True if X not divisible by 2
        y = (Y + 1) // -2 if Y % 2 else Y // 2  # True if Y not divisible by 2

        return x, y

    else:
        x, y = int_to_tuple(num, 2)
        return int_to_tuple(x, size - 1) + (y,)


def isqrt(n):
    """":Return: the largest integer x for which x * x does not exceed n."""
    # Newton's method, via http://stackoverflow.com/a/15391420
    x = n
    y = (x + 1) // 2
    while y < x:
        x = y
        y = (x + n // x) // 2
    return x
NStarman
источник
2

Как насчет чего-то гораздо более простого: учитывая два числа, A и B позволяют str быть конкатенацией: 'A' + ';' + «Б». Тогда пусть выводом будет хеш (str). Я знаю, что это не математический ответ, а простой скрипт на python (который имеет встроенную хэш-функцию) должен выполнить эту работу.

Мадхав Накар
источник
2
но (8,11) и (81,1) отображаются на одно и то же число 811
Леви L
Это хороший момент. Вы можете решить эту проблему, просто добавив символ в середине. Таким образом, для (8, 11) хеш-строки «8-11» и для (81, 1) хеш-строки «81-1». Так что в общем случае для (A, B) хэшируется строка «AB». (Я знаю, это звучит глупо, но это должно работать).
Мадхав Накар
Это также неправильно, потому что эта задача состоит в том, чтобы отобразить два целых числа в новое целое число, а не строку с символом
Leevi L
Я пришел с точки зрения CS, а не с математической точки зрения (для математических решений посмотрите выше ответы). Я беру два целых числа, превращая их в строку, а затем превращаю в целое число. По сути, да, я сопоставляю два целых числа с новым.
Мадхав Накар
1

То, что вы предлагаете, невозможно. У вас всегда будут столкновения.

Для сопоставления двух объектов другому отдельному набору сопоставленный набор должен иметь минимальный размер числа ожидаемых комбинаций:

Предполагая 32-разрядное целое число, у вас есть 2147483647 натуральных чисел. Выбор двух из них, где порядок не имеет значения, с повторением дает 2305843008139952128 комбинаций. Это не очень хорошо вписывается в набор 32-битных целых чисел.

Однако вы можете разместить это отображение в 61 бит. Использование 64-разрядного целого числа, вероятно, проще всего. Установите старшее слово на меньшее целое и младшее слово на большее.

ЖХ.
источник
1

Скажем, у вас есть 32-разрядное целое число, почему бы просто не переместить A в первую 16-разрядную половину, а B в другую?

def vec_pack(vec):
    return vec[0] + vec[1] * 65536;


def vec_unpack(number):
    return [number % 65536, number // 65536];

Кроме того, что он настолько компактен, насколько это возможно и дешев, чтобы вычислить, действительно классным побочным эффектом является то, что вы можете выполнять векторную математику для упакованного числа.

a = vec_pack([2,4])
b = vec_pack([1,2])

print(vec_unpack(a+b)) # [3, 6] Vector addition
print(vec_unpack(a-b)) # [1, 2] Vector subtraction
print(vec_unpack(a*2)) # [4, 8] Scalar multiplication
Stuffe
источник
0

давайте иметь два числа B и C, кодирующие их в одно число A

A = B + C * N

где

B = A% N = B

C = A / N = C

Анкур Чаухан
источник
2
Как вы выбираете N, чтобы сделать это представление уникальным? Если вы решите эту проблему, чем этот ответ будет отличаться от приведенного выше?
чернослив
Вы должны добавить, что N должно быть больше, чем B и C.
Радослав Стоянов
0

Учитывая положительные целые числа A и B, пусть D = количество цифр A имеет, а E = количество цифр B имеет. Результатом может быть объединение D, 0, E, 0, A и B.

Пример: A = 300, B = 12. D = 3, E = 2, результат = 302030012. Это использует тот факт, что единственным числом, начинающимся с 0, является 0,

Pro: Легко кодировать, легко декодировать, удобочитаемый, сначала можно сравнить значимые цифры, возможность сравнения без вычислений, простая проверка ошибок.

Минусы: размер результатов является проблемой. Но это нормально, почему мы в любом случае храним неограниченные целые числа в компьютере.

Пан Пяо
источник
0

Если вы хотите больше контроля, например, выделите биты X для первого числа и биты Y для второго числа, вы можете использовать этот код:

class NumsCombiner
{

    int num_a_bits_size;
    int num_b_bits_size;

    int BitsExtract(int number, int k, int p)
    {
        return (((1 << k) - 1) & (number >> (p - 1)));
    }

public:
    NumsCombiner(int num_a_bits_size, int num_b_bits_size)
    {
        this->num_a_bits_size = num_a_bits_size;
        this->num_b_bits_size = num_b_bits_size;
    }

    int StoreAB(int num_a, int num_b)
    {
        return (num_b << num_a_bits_size) | num_a;
    }

    int GetNumA(int bnum)
    {
        return BitsExtract(bnum, num_a_bits_size, 1);
    }

    int GetNumB(int bnum)
    {
        return BitsExtract(bnum, num_b_bits_size, num_a_bits_size + 1);
    }
};

Я использую всего 32 бита. Идея здесь в том, что если вы хотите, например, чтобы первое число было до 10 бит, а второе число до 12 бит, вы можете сделать это:

NumsCombiner nums_mapper(10/*bits for first number*/, 12/*bits for second number*/);

Теперь вы можете хранить в num_aмаксимальном количестве 2^10 - 1 = 1023и в num_bмаксимальном значении 2^12 - 1 = 4095.

Чтобы установить значение для числа A и числа B:

int bnum = nums_mapper.StoreAB(10/*value for a*/, 12 /*value from b*/);

Теперь bnumвсе биты (всего 32 бита. Вы можете изменить код, чтобы использовать 64 бита). Чтобы получить число:

int a = nums_mapper.GetNumA(bnum);

Чтобы получить число б:

int b = nums_mapper.GetNumB(bnum);

РЕДАКТИРОВАТЬ: bnumможет храниться в классе. Я этого не делал, потому что для собственных нужд я поделился кодом и надеюсь, что он будет полезен.

Спасибо за источник: https://www.geeksforgeeks.org/extract-k-bits-given-position-number/ за функцию извлечения битов и спасибо также за mouvicielответ в этом посте. Используя эти источники, я смог найти более продвинутое решение.

gil123
источник