İki tamsayıyı benzersiz ve belirleyici bir şekilde eşleme


235

İki pozitif A ve B tamsayısını düşünün. Bu ikisini tek bir tamsayı C'de birleştirmek istiyorum.

C ile birleştirilen başka D ve E tam sayıları olamaz. Dolayısıyla, bunları toplama operatörü ile birleştirmek işe yaramaz. Örneğin 30 + 10 = 40 = 40 + 0 = 39 + 1 Birleştirme de işe yaramaz. Örneğin, "31" + "2" = 312 = "3" + "12"

Bu kombinasyon işlemi de deterministik olmalıdır (her zaman aynı girdilerle aynı sonucu verir) ve her zaman tamsayıların pozitif veya negatif tarafında bir tamsayı vermelidir.


10
Yazılımda tamsayı veya matematikte tamsayı kastediyorsanız açıklığa kavuşturmalısınız. Yazılımda, herhangi bir tamsayı türünü seçersiniz ve boyutuna sahip olursunuz, bu nedenle bunların sınırlı bir sayısına sahip olursunuz, bu nedenle bir çözüm yoktur (elbette, giriş verilerinizin bir aralıkta olması garanti edilmez ve çıktınız herhangi bir tamsayı). Matematikte ASk'ın çözümüne bakınız.
Daniel Daranas

Düşük, pozitif bir aralıktaki sınırlı tamsayılardan bahsediyorum. 0 ila 10.000 deyin
zarar

27
@harm: Peki ya sadece 10,001*A + B?
BlueRaja - Danny Pflughoeft

2
: Bu PHP fonksiyonları buldum gist.github.com/hannesl/8031402
cakan

Eğer sipariş önemli değilse, örneğin: (3,12) & (12,3) aynı sonucu
verirse

Yanıtlar:


233

İki yönlü bir NxN -> Nharita arıyorsunuz . Bunlar örneğin kırlangıç için kullanılır . Eşleştirme işlevlerine giriş için bu PDF'ye göz atın . Wikipedia, Cantor eşleştirme işlevi olan belirli bir eşleştirme işlevi sunar :

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

Üç açıklama:

  • Diğerlerinin de belirttiği gibi, bir eşleştirme işlevi uygulamayı planlıyorsanız, yakında keyfi olarak büyük tamsayılara (bignumlar) ihtiyacınız olduğunu görebilirsiniz.
  • (A, b) ve (b, a) çiftleri arasında bir ayrım yapmak istemiyorsanız, eşleştirme işlevini uygulamadan önce a ve b'yi sıralayın.
  • Aslında yalan söyledim. İki yönlü bir ZxZ -> Nharita arıyorsunuz . Cantor işlevi yalnızca negatif olmayan sayılar üzerinde çalışır. Ancak bu bir sorun değildir, çünkü böyle bir bijection tanımlamak kolaydır f : Z -> N:
    • n> = 0 ise f (n) = n * 2
    • n <0 ise f (n) = -n * 2-1

13
+1 Bence bu sınırsız tamsayılar için doğru cevap.
Bilinmiyor

4
Tekrar k1, k2 değerini nasıl alabilirim?
MinuMaster

3
@ MinuMaster: aynı Wikipedia makalesinde, Cantor eşleştirme işlevini Ters Çevirme altında açıklanmaktadır .
Stephan202

4
Ayrıca bkz. Aşağıda newfal tarafından açıklanan Szudzik işlevi.
OliJG

1
Bu, sınırsız tamsayılar için doğru olsa da, sınırlı tamsayılar için en iyisi değildir. Bence @ blue-raja'nın yorumu çok mantıklı.
Kardasis

226

Cantor eşleştirme işlevi , basit, hızlı ve alan açısından verimli olduğu düşünüldüğünde gerçekten daha iyi olanlardan biridir, ancak Wolfram'da Matthew Szudzik tarafından daha iyi yayınlanan bir şey var . Cantor eşleştirme işlevinin (göreceli olarak) sınırlanması 2N, girişler iki Nbit tamsayı ise, kodlanmış sonuç aralığının her zaman bir bit tamsayısının sınırları içinde kalmamasıdır . Yani, eğer girişlerim iki 16bitlik tamsayılar arasındaysa 0 to 2^16 -1, o zaman 2^16 * (2^16 -1)olası giriş kombinasyonları vardır , bu yüzden bariz Pigeonhole Prensibi ile , en azından 2^16 * (2^16 -1), yani 2^32 - 2^16bir haritaya eşit veya başka bir deyişle,32bit sayıları ideal olarak mümkün olmalıdır. Programlama dünyasında bu pek pratik bir öneme sahip olmayabilir.

Cantor eşleştirme işlevi :

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

İki maksimum en fazla 16 bit tam sayı (65535, 65535) için eşleme, gördüğünüz gibi 32 bite sığamayacak 8589803520 olacaktır.

Szudzik işlevini girin :

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

(65535, 65535) için eşleme şimdi gördüğünüz gibi 32 bit (0 ila 2 ^ 32 -1) tam sayı olan 4294967295 olacaktır. Burası bu çözümün ideal olduğu yerdir, o alandaki her noktayı kullanır, böylece hiçbir şey daha fazla yer tasarrufu sağlayamaz.


Şimdi, tipik olarak, diller / çerçevelerdeki çeşitli boyutlarda sayıların imzalı uygulamalarını ele aldığımızı göz önünde bulundurarak, aralarındaki signed 16bit tamsayılarını ele alalım -(2^15) to 2^15 -1(daha sonra çıkışın bile işaretli aralığa yayılmasını nasıl uzatacağımızı göreceğiz). O zamandan beri ave bpozitif olmak zorundalar 0 to 2^15 - 1.

Cantor eşleştirme işlevi :

İki en çok 16 bit işaretli tam sayı (32767, 32767) için eşleme 2147418112 olacak ve işaretli 32 bit tam sayı için maksimum değerin sadece kısa.

Şimdi Szudzik'in işlevi :

(32767, 32767) => 1073741823, çok daha küçük ..

Negatif tamsayıları açıklayalım. Bu bildiğim orijinal sorunun ötesinde, ancak gelecekteki ziyaretçilere yardımcı olmak için ayrıntılı.

Cantor eşleştirme işlevi :

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 olan Int64. 16 bit girişler için 64 bit çıkış çok affedilmez olabilir !!

Szudzik'in işlevi :

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, imzasız aralık için 32 bit veya işaretli aralık için 64 bit, ancak yine de daha iyi.

Şimdi tüm bunlar çıktı her zaman pozitif olmuştur. İmzalı dünyada, çıktının yarısını negatif eksene aktarabilirsek daha fazla yer tasarrufu sağlayacaktır . Szudzik's için şu şekilde yapabilirsiniz:

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

Yaptığım şey: 2Girdilere bir ağırlık uyguladıktan ve işlevden geçtikten sonra, çıkışı ikiye bölerim ve bir kısmını çarparak negatif eksene götürürüm -1.

Sonuçlara bakın, işaretli bir 16bit sayısı aralığındaki herhangi bir girdi için , çıktı 32, serin olan işaretli bir bit tamsayısının sınırları içinde yer alır . Nasıl Cantor eşleştirme işlevi için aynı şekilde gitmek emin değilim ama onun kadar etkili değil kadar denemedim. Ayrıca, Cantor eşleştirme işlevinde daha fazla hesaplama yapılması onun daha yavaş olduğu anlamına gelir .

İşte bir C # uygulaması.

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;
}

Ara hesaplamalar 2Nişaretli tamsayı sınırlarını aşabileceğinden , 4Ntamsayı türünü kullandım (son bölüme 2sonucu geri getirir 2N).

Alternatif çözüm üzerinde sağladığım bağlantı, uzayda her bir noktayı kullanan fonksiyonun bir grafiğini güzel bir şekilde tasvir ediyor. Bir çift koordinatı geri dönüşümlü olarak tek bir sayıya benzersiz bir şekilde kodlayabileceğinizi görmek şaşırtıcı! Sayıların sihirli dünyası !!


5
İşaretli tamsayılar için değiştirilmiş unhash işlevi ne olurdu?
Arets Paeglis

7
Bu cevap beni karıştırıyor. Eşlemek istiyorsanız (0,0)aracılığıyla (65535,65535)tek bir numara, sonra a<<16 + btemelde her şekilde daha iyidir (daha hızlı, daha basit, daha kolay, daha belirgin, anlamak) . İsterseniz (-32768,-32768)için (327687,327687)bunun yerine, sadece konu 32768 ilki.
BlueRaja - Danny Pflughoeft

2
@ BlueRaja-DannyPflughoeft haklısın. Aralık sınırlı veya bilinmiyorsa cevabım geçerlidir. Ben güncelleyeceğim. Sınırdan önce benim için önemli olduğunu yazmıştım. Bu cevabı düzenlemek uzun süredir aklımda. Yakında zaman bulacağım.
nawfal

Szudzik'in işlevi kombinasyonlar veya permütasyonlar için çalışır mı? Permütasyon gibi görünüyor değil mi? Kombinasyon için kullanmak istersem algoritmanın IF ve Else kısımlarını ortadan kaldırabilir miyim?
Jamie Marshall


47

A ve B 2 bayt ile ifade edilebilirse, bunları 4 bayt üzerinde birleştirebilirsiniz. A'yı en önemli yarıya ve B'yi en önemli yarıya koyun.

C dilinde (sizeof (kısa) = 2 ve sizeof (int) = 4 varsayarak):

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

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

short getB(int C)
{
    return C & 0xFFFF;
}

3
combine()Olmalı return (unsigned short)(A<<16) | (unsigned short)(B); Böylece negatif sayılar düzgün bir şekilde paketlenebilir.
Andy

2
@Andy A<<16sınırların dışına çıkacak. O olmalıreturn (unsigned int)(A<<16) | (unsigned short)(B);
DanSkeel

15

Bu mümkün mü?
İki tamsayıyı birleştiriyorsunuz. İkisi de -2.147.483.648 ila 2.147.483.647 aralığına sahiptir, ancak yalnızca pozitifleri alacaksınız. Bu 2147483647 ^ 2 = 4,61169E + 18 kombinasyon yapar. Her kombinasyonun benzersiz olması ve bir tamsayı ile sonuçlanması gerektiğinden, bu miktarda sayı içerebilen bir tür sihirli tamsayıya ihtiyacınız olacaktır.

Yoksa mantığım kusurlu mu?


+1 Ben de öyle düşünüyorum (A ve B'nin sırasını söyleyerek hesaplama yapmama rağmen)
lc.

4
Evet, mantığınız güvercin deliği prensibi ile doğrudur. Neyse ki asker tamsayıya bağlı olup olmadığını belirtmedi.
Bilinmiyor

Evet, sonradan da düşündüm, ama mesajın özünde aynı olduğunu düşündüm, bu yüzden yeniden düzenlemeyi zahmet etmedim.
Boris Callens

Ayrıca, şans hesaplamamı (Hollandacadan gerçek tercüme) tekrar almam gerektiğini fark ettim.
Boris Callens

2
@Boris: Kansrekening "olasılık teorisi" dir.
Stephan202

8

Pozitif tamsayılar için standart matematiksel yol, asal çarpanlara ayırmanın benzersizliğini kullanmaktır.

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

Dezavantajı, görüntünün oldukça geniş bir tamsayı aralığına yayılma eğiliminde olmasıdır, bu nedenle bir bilgisayar algoritmasında eşlemeyi ifade etmek söz konusu olduğunda, sonuç için uygun bir tür seçmeyle ilgili sorunlar yaşayabilirsiniz.

Negatif ile başa çıkmak xve y5 ve 7 terim gücüne sahip bayrakları kodlamak için bunu değiştirebilirsiniz .

Örneğin

f( x, y ) -> 2^|x| * 3^|y| * 5^(x<0) * 7^(y<0)

Matematik iyi. Ancak, Boris'in dediği gibi, bunu bir bilgisayar programı olarak çalıştırmak istiyorsanız, makinenin sonluluğunu dikkate almalısınız. Algoritma, ilgili makinede temsil edilebilen tam sayıların bir alt kümesi için doğru şekilde çalışacaktır.
Yuval F

2
Bunu ikinci paragrafımda belirtmiştim. Sorudaki etiketler, belirli bir dili değil, 'algoritmayı', 'matematiksel' ve 'deterministik' gösterir. Giriş aralığı sınırlı olmayabilir ve ortamın sınırsız tamsayı türü 'bigint' olabilir.
CB Bailey

8

Sayı abirincisi, bikincisi olsun. Izin polmak a+1oyunu bırakanların asal sayı, qolmak b+1oyunu bırakanların asal sayı

O zaman, sonuç pq, eğer a<b,ya da 2pqeğer a>b. Eğer a=böyle olsun p^2.


4
Bir NP çözümü isteyeceğinizden şüpheliyim.
user44242

1
Bu, a = 5, b = 14 ve a = 6, b = 15 için aynı sonucu üretmiyor mu?
Lieven Keersmaekers

3
İki farklı primere sahip iki ürün aynı sonuca sahip olamaz (benzersiz ana faktör ayrışımı) a = 5, b = 14 -> sonuç 13 * 47 = 611 a = 6, b = 15 -> sonuç 17 * 53 = 901
099'da

4

Bir harita oluşturmak o kadar da zor değil:

   1 2 3 4 5 (a, b)! = (B, a) ise bu eşlemeyi kullanın
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) (ayna) ise bu eşlemeyi kullanın
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 Negatif / pozitif ihtiyacınız varsa bunu kullanın
 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

Keyfi a, b için değerin nasıl elde edileceğini bulmak biraz daha zordur.


4

f(a, b) = s(a+b) + a, nerede s(n) = n*(n+1)/2

  • Bu bir işlevdir - deterministiktir.
  • Ayrıca injective - f farklı (a, b) çiftleri için farklı değerleri eşler. Sen gerçeği kullanarak bu kanıtlayabilirim: s(a+b+1)-s(a+b) = a+b+1 < a.
  • Oldukça küçük değerler döndürür - eğer dizi büyük olmak zorunda olmadığından dizi indeksleme için kullanacaksanız iyi olur.
  • Önbellek dostudur - iki (a, b) çifti birbirine yakınsa, f birbirine yakın olan sayıları (diğer yöntemlere kıyasla) eşler.

Ne demek istediğini anlamadım:

tamsayıların pozitif veya negatif tarafında her zaman bir tamsayı vermelidir

Bu foruma nasıl (büyük), (küçük) karakter yazabilirim?


2
Karakterlerden daha büyük ve daha az karakter içinde iyi çalışmalıdır backtick escapes.
TRiG

Bu, Cantor eşleştirme işlevine eşdeğerdir ve bu nedenle negatif tamsayılarla çalışmaz.
Davor Josipoviç

4

Stephan202'nin cevabı gerçekten genel olan tek cevap olmasına rağmen, sınırlı aralıktaki tamsayılar için daha iyisini yapabilirsiniz. Örneğin, aralığınız 0..10.000 ise, şunları yapabilirsiniz:

#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));
}

Sonuçlar, tamsayı tipinin kardinalitesinin kareköküne kadar bir aralık için tek bir tamsayıya sığabilir. Bu, Stephan202'nin daha genel yönteminden biraz daha verimli bir şekilde paketlenir. Kod çözülmesi de oldukça basittir; Yeni başlayanlar için karekök gerektirmez :)


Şamandıralar için herhangi bir şans mümkün mü?
Lukas


3

Şunları kontrol edin: http://en.wikipedia.org/wiki/Pigeonhole_principle . A, B ve C aynı türdeyse, yapılamaz. A ve B 16 bit tamsayılar ve C 32 bit ise, yalnızca kaydırma özelliğini kullanabilirsiniz.

Karma algoritmaların doğası, her farklı girdi için benzersiz bir karma sağlayamamalarıdır.


2

@Nawfal tarafından verilen yönteme göre @DoctorJ kodunun sınırsız tamsayılara bir uzantısı. Kodlayabilir ve kodunu çözebilir. Normal diziler ve numpy dizilerle çalışır.

#!/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

2

Çok daha basit bir şeye ne dersiniz: İki sayı verildiğinde A ve B, birleştirme olsun: 'A' + ';' + 'B'. Sonra çıktının hash (str) olmasına izin verin. Bu matematiksel bir cevap değil biliyorum, ama basit bir python (hangi bir yerleşik karma işlevi vardır) komut dosyası iş yapmak gerekir.


2
ancak (8,11) ve (81,1) aynı numaraya eşlenir 811
Leevi L

Bu iyi bir nokta. Ortaya bir sembol ekleyerek bu sorunu çözebilirsiniz. Yani (8, 11) hash için "8-11" dizesi ve (81, 1) hash için "81-1" dizesi hash. Yani genel olarak (A, B) için "AB" dizgisi vardır. (Kulağa kaba geldiğini biliyorum, ama işe yaramalı).
Madhav Nakar

bu da yanlış çünkü bu görev iki tamsayıyı yeni bir tamsayı ile
eşleştirmek

Matematiksel bir bakış açısı yerine bir CS perspektifinden geliyorum (matematiksel çözümler için yukarıdaki yanıtlara bakın). İki tamsayı alıyorum, bir tamsayı haline geldiğinde onları bir dizeye dönüştürüyorum. Aslında evet, iki tamsayıyı yenisiyle eşleştiriyorum.
Madhav Nakar

1

Önerdiğiniz şey imkansız. Her zaman çarpışma olur.

İki nesneyi başka bir kümeyle eşlemek için, eşlenen kümenin beklenen kombinasyon sayısının minimum boyutuna sahip olması gerekir:

32 bitlik bir tamsayı varsayalım, 2147483647 pozitif tamsayılarınız var. Siparişin önemli olmadığı ve tekrarlama ile bunlardan iki tanesinin seçilmesi 2305843008139952128 kombinasyonları verir. Bu, 32 bitlik tamsayılar kümesine iyi uymuyor.

Bununla birlikte, bu eşlemeyi 61 bite sığdırabilirsiniz. 64 bit tam sayı kullanmak muhtemelen en kolayıdır. Yüksek kelimeyi daha küçük tamsayıya, düşük kelimeyi daha büyük tamsayıya ayarlayın.


1

32 bitlik bir tam sayıya sahip olduğunuzu varsayalım, neden A'yı ilk 16 bitlik yarıya ve B'yi diğerine taşımakla kalmıyorsunuz?

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


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

Bunun olabildiğince az yer kaplaması ve hesaplaması ucuz olması dışında, gerçekten harika bir yan etki, paketlenmiş sayı üzerinde vektör matematiği yapabilmenizdir.

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

0

iki tane B ve C'ye sahip olalım, onları tek bir sayı A'ya kodlayalım

A = B + C * N

nerede

B = A% N = B

C = A / N = C


2
Bu temsili benzersiz kılmak için N'yi nasıl seçersiniz? Bu sorunu çözerseniz, bu cevap yukarıdaki yanıtlardan nasıl farklıdır?
Erik

N'nin hem B hem de C'den daha büyük olması gerektiğini eklemelisiniz
Radoslav Stoyanov

0

Pozitif A ve B tamsayıları verildiğinde, D = A basamak sayısı ve E = B basamak sayısı vardır Sonuç D, 0, E, 0, A ve B'nin bir birleşimi olabilir.

Örnek: A = 300, B = 12. D = 3, E = 2 sonuç = 302030012. Bu, 0 ile başlayan tek sayının 0,

Pro: Kodlaması kolay, kodunu çözmek kolay, insan tarafından okunabilir, önemli basamaklar ilk önce karşılaştırılabilir, hesaplama olmadan karşılaştırma potansiyeli, basit hata kontrolü.

Eksileri: Sonuçların boyutu bir sorundur. Ama sorun değil, neden sınırsız tam sayıları bir bilgisayarda saklıyoruz?


0

İlk sayı için X biti ve ikinci sayı için Y biti gibi daha fazla denetim istiyorsanız, şu kodu kullanabilirsiniz:

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);
    }
};

Toplam 32 bit kullanıyorum. Buradaki fikir, örneğin ilk sayının 10 bite, ikinci sayının 12 bite kadar olmasını istiyorsanız, bunu yapabilirsiniz:

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

Şimdi saklayabileceğiniz num_amaksimum sayı 2^10 - 1 = 1023ve num_biçinde naximum değeri 2^12 - 1 = 4095.

Num A ve num B için değer ayarlamak için:

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

Şimdi bnumtüm bitler (toplam 32 bit. 64 bit kullanmak için kodu değiştirebilirsiniz) Num a almak için:

int a = nums_mapper.GetNumA(bnum);

Num b almak için:

int b = nums_mapper.GetNumB(bnum);

EDIT: bnumsınıf içinde saklanabilir. Ben kendi ihtiyaçlarını kod paylaştı ve yardımcı olacağını umuyoruz çünkü ben yapmadım.

Kaynak için teşekkürler: https://www.geeksforgeeks.org/extract-k-bits-given-position-number/ işlevi bit ayıklama işlevi için ve mouvicielbu yazıya cevap için teşekkürler . Bunları kaynaklara kullanarak daha gelişmiş bir çözüm bulabilirim

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.