Wyobraź sobie dwie dodatnie liczby całkowite A i B. Chcę połączyć te dwie w jedną liczbę całkowitą C.
Nie może być innych liczb całkowitych D i E, które łączą się z C. Tak więc łączenie ich z operatorem dodawania nie działa. Np. 30 + 10 = 40 = 40 + 0 = 39 + 1 Nie działa też konkatynacja. Np. „31” + „2” = 312 = „3” + „12”
Ta kombinacja operacji powinna również być deterministyczna (zawsze dawać ten sam wynik przy tych samych danych wejściowych) i zawsze powinna dawać liczbę całkowitą po stronie dodatniej lub ujemnej liczb całkowitych.
10,001*A + B
?Odpowiedzi:
Szukasz
NxN -> N
mapowania bijective . Służą one np . Dovetailing . Zapoznaj się z tym plikiem PDF, aby uzyskać wprowadzenie do tak zwanych funkcji parowania . Wikipedia wprowadza określoną funkcję parowania, a mianowicie funkcję parowania Cantor :Trzy uwagi:
ZxZ -> N
mapowania bijective . Funkcja Cantora działa tylko na liczbach nieujemnych. Nie stanowi to jednak problemu, ponieważ łatwo zdefiniować bijectionf : Z -> N
, tak jak poniżej :źródło
Funkcja parowania kantora jest naprawdę jedną z lepszych, ponieważ jest prosta, szybka i zajmuje mało miejsca, ale jest coś jeszcze lepiej opublikowanego w Wolfram przez Matthew Szudzika tutaj . Ograniczeniem funkcji parowania Cantora (względnie) jest to, że zakres zakodowanych wyników nie zawsze mieści się w granicach
2N
bitowej liczby całkowitej, jeśli dane wejściowe są dwiemaN
liczbami całkowitymi. Oznacza to, że jeśli moje dane wejściowe są16
liczbami całkowitymi od dwóch bitów0 to 2^16 -1
, to możliwe są2^16 * (2^16 -1)
kombinacje danych wejściowych, więc zgodnie z oczywistą zasadą Pigeonhole potrzebujemy wyjścia o wielkości co najmniej2^16 * (2^16 -1)
równej2^32 - 2^16
lub innymi słowy mapie32
idealnie powinny być możliwe liczby bitowe. To może nie mieć praktycznego znaczenia w świecie programowania.Funkcja parowania kantora :
Wejdź w funkcję Szudzika :
Teraz, biorąc pod uwagę fakt, że zwykle mamy do czynienia z podpisanymi implementacjami liczb o różnych rozmiarach w językach / frameworkach, rozważmy
signed 16
liczby całkowite od --(2^15) to 2^15 -1
(później zobaczymy, jak rozszerzyć nawet wyjście do zakresu ponad podpisany zakres). Oda
ib
muszą być pozytywne, różnią się od0 to 2^15 - 1
.Funkcja parowania kantora :
Teraz funkcja Szudzika :
Rozważmy liczby całkowite ujemne. To jest poza pierwotnym pytaniem, które znam, ale po prostu opracowaniem, aby pomóc przyszłym użytkownikom.
Funkcja parowania kantora :
Funkcja Szudzika :
Wszystko to, podczas gdy wyniki zawsze były pozytywne. W podpisanym świecie zaoszczędzenie miejsca zajmowałoby jeszcze więcej, gdybyśmy mogli przenieść połowę mocy wyjściowej na oś ujemną . Możesz to zrobić w ten sposób dla Szudzika:
Co robię: po nałożeniu ciężaru
2
na dane wejściowe i przejściu przez funkcję dzielę wyjście przez dwa i przenoszę niektóre z nich na oś ujemną, mnożąc przez-1
.Zobacz wyniki, dla dowolnego wejścia w zakresie liczby
16
bitów ze znakiem , wyjście leży w granicach32
fajnej liczby całkowitej ze znakiem . Nie jestem pewien, jak postąpić w ten sam sposób dla funkcji parowania Cantor, ale nie próbowałem tyle, ile nie jest tak wydajna. Co więcej, więcej obliczeń związanych z funkcją parowania Cantora oznacza również jego spowolnienie .Oto implementacja C #.
Ponieważ obliczenia pośrednie mogą przekraczać limity liczby
2N
całkowitej ze znakiem, użyłem4N
typu liczby całkowitej (ostatni podział przez2
powoduje powrót wyniku2N
).Link, który podałem w alternatywnym rozwiązaniu, ładnie przedstawia wykres funkcji wykorzystującej każdy pojedynczy punkt w przestrzeni. To niesamowite, że możesz jednoznacznie zakodować parę współrzędnych w pojedynczą liczbę w sposób odwracalny! Magiczny świat liczb !!
źródło
(0,0)
thru(65535,65535)
do jednego numeru, a następniea<<16 + b
jest lepszy w zasadzie każdy sposób (szybsze, prostsze, łatwiejsze do zrozumienia, bardziej oczywiste) . Jeśli chcesz(-32768,-32768)
, aby(327687,327687)
zamiast tego po prostu przedmiotem 32768 pierwszy.Jeśli A i B można wyrazić za pomocą 2 bajtów, możesz je połączyć na 4 bajtach. Połóż A na najbardziej znaczącej połowie, a B na najmniej znaczącej połowie.
W języku C daje to (przy założeniu sizeof (short) = 2 i sizeof (int) = 4):
źródło
combine()
powinienreturn (unsigned short)(A<<16) | (unsigned short)(B);
Aby liczby ujemne mogły być odpowiednio zapakowane.A<<16
wyjdzie poza granice. Powinno byćreturn (unsigned int)(A<<16) | (unsigned short)(B);
Czy to w ogóle możliwe?
Łączycie dwie liczby całkowite. Oba mają zakres od -2 147 483 648 do 2 147 483 647, ale weźmiesz tylko pozytywy. To sprawia, że 2147483647 ^ 2 = 4,61169E + 18 kombinacji. Ponieważ każda kombinacja musi być unikalna ORAZ wynikać z liczby całkowitej, będziesz potrzebować jakiejś magicznej liczby całkowitej, która może zawierać taką liczbę liczb.
Czy moja logika jest wadliwa?
źródło
Standardowym matematycznym sposobem na dodatnie liczby całkowite jest użycie unikatowości faktoryzacji pierwotnej.
Minusem jest to, że obraz ma tendencję do rozciągania się na całkiem szeroki zakres liczb całkowitych, więc jeśli chodzi o wyrażenie odwzorowania w algorytmie komputerowym, możesz mieć problemy z wyborem odpowiedniego typu dla wyniku.
Możesz to zmienić, aby radzić sobie z negatywnymi
x
iy
kodując flagi o potęgach 5 i 7 terminów.na przykład
źródło
Niech liczba
a
będzie pierwszą,b
drugą. Niechp
będziea+1
-tą liczbą pierwszą,q
byćb+1
-tą liczbą pierwsząZatem wynikiem jest
pq
, jeślia<b,
lub2pq
jeślia>b
. Jeśli taka=b
, niech tak będziep^2
.źródło
Stworzenie mapowania nie jest trudne:
Ustalenie, w jaki sposób uzyskać wartość dla dowolnego a, b, jest nieco trudniejsze.
źródło
f(a, b) = s(a+b) + a
, gdzies(n) = n*(n+1)/2
s(a+b+1)-s(a+b) = a+b+1 < a
.Nie rozumiem, co masz na myśli przez:
Jak pisać (większe niż), (mniej niż) znaki na tym forum?
źródło
backtick escapes
.Chociaż odpowiedź Stephan202 jest jedyną naprawdę ogólną, w przypadku liczb całkowitych z ograniczonego zakresu można lepiej. Na przykład, jeśli twój zakres wynosi 0..10 000, możesz:
Wyniki mogą zmieścić się w jednej liczbie całkowitej dla zakresu do pierwiastka kwadratowego z liczności typu liczb całkowitych. Pakuje się to nieco wydajniej niż ogólniejsza metoda Stephan202. Dekodowanie jest również znacznie prostsze; nie wymagające pierwiastków kwadratowych, na początek :)
źródło
W przypadku dodatnich liczb całkowitych jako argumentów i gdy kolejność argumentów nie ma znaczenia:
Oto nieuporządkowana funkcja parowania :
Dla x ≠ y, oto unikalna funkcja nieuporządkowanego parowania :
źródło
Sprawdź to: http://en.wikipedia.org/wiki/Pigeonhole_principle . Jeśli A, B i C są tego samego typu, nie można tego zrobić. Jeśli A i B to 16-bitowe liczby całkowite, a C to 32-bit, możesz po prostu użyć przesunięcia.
Sama natura algorytmów mieszających polega na tym, że nie mogą one zapewnić unikatowego skrótu dla każdego innego wejścia.
źródło
Oto rozszerzenie kodu @DoctorJ na nieograniczone liczby całkowite oparte na metodzie podanej przez @nawfal. Może kodować i dekodować. Działa z normalnymi tablicami i tablicami liczbowymi.
źródło
Co powiesz na coś o wiele prostszego: Biorąc pod uwagę dwie liczby, A i B niech będą stratatation: 'A' + ';' + „B”. Niech wyjście będzie hash (str). Wiem, że nie jest to matematyczna odpowiedź, ale prosty skrypt python (który ma wbudowaną funkcję skrótu) powinien wykonać to zadanie.
źródło
To, co sugerujesz, jest niemożliwe. Zawsze będziesz mieć kolizje.
Aby zmapować dwa obiekty na inny pojedynczy zestaw, zmapowany zestaw musi mieć minimalną wielkość oczekiwanej liczby kombinacji:
Zakładając 32-bitową liczbę całkowitą, masz 2147483647 liczb całkowitych dodatnich. Wybranie dwóch z nich, w przypadku których kolejność nie ma znaczenia i przy powtarzaniu daje 2305843008139952128 kombinacji. Nie pasuje to dobrze do zestawu 32-bitowych liczb całkowitych.
Możesz jednak zmieścić to mapowanie w 61 bitach. Korzystanie z 64-bitowej liczby całkowitej jest prawdopodobnie najłatwiejsze. Ustaw wysokie słowo na mniejszą liczbę całkowitą, a niskie słowo na większą.
źródło
Załóżmy, że masz 32-bitową liczbę całkowitą. Dlaczego nie przenieść A do pierwszej 16-bitowej połowy, a B do drugiej?
Poza tym, że jest tak wydajny, jak to tylko możliwe i tani w obliczeniach, naprawdę fajnym efektem ubocznym jest to, że możesz wykonać matematykę wektorową na zapakowanej liczbie.
źródło
niech mamy dwie liczby B i C, kodując je w jedną liczbę A.
A = B + C * N
gdzie
B = A% N = B
C = A / N = C
źródło
Biorąc pod uwagę dodatnie liczby całkowite A i B, niech D = liczba cyfr A ma, a E = liczba cyfr B ma Wynik może być połączeniem D, 0, E, 0, A i B.
Przykład: A = 300, B = 12. D = 3, E = 2 wynik = 302030012. Wykorzystuje to fakt, że jedyną liczbą rozpoczynającą się od 0 jest 0,
Pro: Łatwe do kodowania, łatwe do odkodowania, czytelne dla człowieka, cyfry znaczące można najpierw porównać, możliwość porównania bez obliczeń, proste sprawdzanie błędów.
Minusy: Rozmiar wyników jest problemem. Ale to w porządku, dlaczego i tak przechowujemy w komputerze nieograniczone liczby całkowite.
źródło
Jeśli chcesz mieć większą kontrolę, na przykład alokuj bity X dla pierwszej liczby i bity Y dla drugiej liczby, możesz użyć tego kodu:
Używam w sumie 32 bitów. Chodzi o to, że jeśli chcesz na przykład, aby pierwsza liczba wynosiła do 10 bitów, a druga liczba do 12 bitów, możesz to zrobić:
Teraz możesz przechowywać w
num_a
maksymalnej liczbie, która jest2^10 - 1 = 1023
wnum_b
naximum wartości2^12 - 1 = 4095
.Aby ustawić wartość dla liczb A i B:
Teraz
bnum
są wszystkie bity (łącznie 32 bity. Możesz zmodyfikować kod, aby używał 64 bitów) Aby uzyskać num a:Aby uzyskać num b:
EDYCJA:
bnum
może być przechowywana wewnątrz klasy. Nie zrobiłem tego, ponieważ własne potrzeby podzieliłem kod i mam nadzieję, że będzie on pomocny.Dzięki za źródło: https://www.geeksforgeeks.org/extract-k-bits-given-position-number/ za funkcję wyodrębniania bitów i dziękuję również za
mouviciel
odpowiedź w tym poście. Używając ich do źródeł, mogłem znaleźć bardziej zaawansowane rozwiązanieźródło