Zastanawiam się tylko, jak gry takie jak Tap titans i Cookie Clicker radzą sobie z tak dużymi liczbami.
Próbuję wdrożyć grę w trybie bezczynności, jednak największy format liczb obsługiwany przez C # jest dziesiętny.
Szukam wsparcia do 10 ^ 500; to musi być zmiennoprzecinkowe
Jak mogłem sobie z tym poradzić?
PS musi to być platforma, tj. PC, Mac, iOS, Android i kompatybilna z Unity
unity
mathematics
MathHelp
źródło
źródło
double
. Gdybym to był ja, użyłbym BigInteger .Odpowiedzi:
Jeśli chcesz po prostu przechowywać ogromne liczby bez pełnej dokładności, na przykład, jeśli chcesz pokazać 12.567.000.000.000 jako 12.567T (trylion), możesz po prostu użyć standardowych wartości zmiennoprzecinkowych / dziesiętnych i pokazać pierwsze x znaczących liczb, z odpowiednim przyrostkiem lubię to. Czy gdy jesteś w oktylionach, naprawdę musisz dbać o każdy przyrost liczby całkowitej?
źródło
Możesz użyć czegoś takiego jak BigInteger , który jest dostępny tylko w .net 4.0, jeśli się nie mylę (nie jest obsługiwany przez wszystkie platformy budujące jedność).
Istnieje jednak kilka bibliotek, które próbują wprowadzić tę funkcjonalność bez wymagania .net4.0. Na przykład tutaj .
Alternatywnie możesz użyć mniejszych liczb, aby przedstawić większą, śledząc mnożnik. Na przykład:
Teraz, nawet jeśli masz wartość 9, jeśli połączysz ją ze swoim mnożnikiem, możesz skutecznie przedstawić te 9 jako 9 bilionów (albo wpisując „bilion” lub pisząc coś, co doda zera na końcu twojej wartości ).
źródło
BigInteger
reprezentują liczbę w postaci ciągu lub bajtu [] - w efekcie można stworzyć własną klasę, która po prostu dodaje i odejmuje dwie „liczby jako ciągi lub bajty” - ( zazwyczaj ten typ gry nie nie jest to potrzebne, ale można również obsługiwać mnożenie lub dzielenie lub inne bardziej zaawansowane funkcje ) - ale muszą pamiętać, że zawsze istnieje fizyczny limit, w którym może zabraknąć pamięci.Prawdopodobnie będziesz musiał napisać własną klasę do wykorzystania w Unity, ale nie byłoby to szczególnie trudne.
Wewnętrznie może to być lista liczb całkowitych (takich jak a
List<int>
), przy czym każdy element na liście odpowiada grupie 9 cyfr. Każda liczba całkowita będzie miała zakres od 0 do 999 999 999. Liczba całkowita może obsłużyć nieco ponad 2 miliardy, i podwoić ją, jeśli jest niepodpisana, ale będziesz chciał, aby każda „cyfra” była przepełniona1 000 000 000
, ponieważ będziesz również chciał aby móc łatwo przekonwertować dużą liczbę na ciąg znaków do wyświetlenia. Łatwiej jest połączyć istniejące już cyfry dziesiętne (return group[i].ToString() + group[i-1].ToString() and so on
) niż wymyślić, jak wyświetlić sumę grup, które znajdują się poza zakresem dowolnego regularnego typu danych.Pierwszy int na twojej liście reprezentowałby 1s. Następna byłaby liczba miliardów. Następny, liczba biliardów i tak dalej.
Dodawanie i odejmowanie działałoby tak samo, jak dodawanie i odejmowanie za pomocą pisaka i papieru, w którym musisz uważać na przepełnienie i przenosić je do następnej „cyfry”, ale zamiast cyfr o zakresie 0–9, Twoje cyfry mieszczą się w zakresie od Od 0 do 999 999 999.
źródło
Jeśli chodzi o obsługę dużych liczb, przyjrzałbym się temu, co uważam za dobry przykład, jak Wieża Bohatera . Górny lewy róg:
(źródło: mzstatic.com )
Bez wchodzenia w grę sposób, w jaki obsługuje liczby, jest stosunkowo prosty: widać dwa zestawy liczb. Gdy wejdziesz wyżej w wieżę i zarobisz więcej „złota”, dwa wiadra po prostu reprezentują większe liczby.
Gdy gra przejdzie T, przechodzi w a, b, c ... z, aa, ab, ...
Robiąc to w ten sposób, wciąż wiesz, ile złota „zarobiłeś” ... nie zagłębiając się w szczegóły.
Czy naprawdę zależy ci na milionach, gdy twój numer przekroczy biliony?
Czy utrzymuje liczbę w Int, Big Int, Float, Double, Decimal, ...? Tablica niestandardowa? Kiedy traktujesz liczby w tak „niewyraźny” sposób, nie sądzę, żeby to miało znaczenie ...
Wszystko, co najprawdopodobniej ma znaczenie, to najważniejsze części - w tym przypadku pierwsze 6 ... Następnie MAYBE następne 3 lub 6 - od zarobienia kilkuset K może przejść do Milionów - ale jest punkt, w którym można zarobić kilkaset K nie wpłynie na ciebie, gdy trafisz T ... a tym bardziej aa i dalej.
Twój przebieg będzie się różnić (w zależności od tego, czego chcesz / potrzebujesz) ... Pomyślałem, że wydam mój 2c na dobry / prosty przykład.
Edytować:
Dalsze przemyślenia na temat tego, jak zaimplementowałbym system numeracji: miałbym liczbę z 3 istotnymi częściami: XXXX.RRR (...) xZZZ.
Tak więc 120.365x1 będzie 120k365 ... 120.365x2 będzie 120M365K ... itd. Uderz w 4 wiodące (1200.365x2), a następnie po prostu obróć cyfry 1.200365 (...) x3. Bam Masz 1B200M.
XY z łatwością zmieściłby się w liczbach dziesiętnych lub zmiennoprzecinkowych ... z Z siedzącym obok niego jako int / unsigned int.
Za pomocą liczby zmiennoprzecinkowej będziesz w stanie zachować znaczną - ale coraz bardziej nieistotną - liczbę cyfr po kropce.
Z oznaczałoby łatwo zrozumiały blok liczb:
źródło
A łatwym sposobem na obsługę dużych liczb jest po prostu posiadanie więcej niż jednej wartości INTEGER, a następnie PRZENOSZENIE jakiegokolwiek przelewu. Jeśli masz 16-bitową wartość INT (od 0 do 65535) i chcesz mieć więcej, użyj dwóch 16-bitowych wartości INT z rzędu. Pomyśl o tym jak o wartości BYTE (od 0 do 255), ale używającej tylko do 99 cyfr wartości. Gdy osiągnie 100, następnie przewiń go do następnej wyższej wartości BYTE dla tylu cyfr, ile uznasz za przydatne. W dzisiejszych komputerach GHZ nawet takie niechlujne kodowanie jest w porządku.
Oczywiście istnieje alternatywa, która jest nieco szybsza.
Jeśli dodajesz 18 wielokrotnie do liczby, szybciej po prostu odejmij 2 i dodaj 20. 18, 36, 54, 72, 90, 108, ... 18 = 20 + (- 2).
Działa również w trybie binarnym. (Te same wartości dziesiętne w formacie binarnym) 10010, 100100, 110110, 1001000
DEC (18) = BIN (10010)
Z wyjątkiem łatwiejszego parsowania binarnego, należy pomyśleć o 18 = 16 + 2
DEC (16 + 2) = BIN (10000 + 00010). Jeśli wartość wynosiła 15, pomyśl o tym jak o dodaniu 16 w systemie binarnym i odjęciu 1 (10000-00001).
W ten sposób można ograniczyć liczbę porcji do zarządzanych limitów według wartości.
Jeśli używasz niechlujnej metody kodowania ograniczającej podstawową 16-bitową wartość INT (od 0 do 65535) do 4-cyfrowego limitu dziesiętnego (od 0 do 9999), wystarczy, że wartość przekroczy limit 9999, odejmij od niego 9999 i przenieś go do kolejnej porcji wartości (ponieważ robisz w zasadzie „dodajesz i zastępujesz” liczbami w porównaniu do prawdziwego obliczenia binarnego).
Idealnie byłoby po prostu użyć SYMBOLICZNEJ MATY, której nauczyłeś się w szkole podstawowej. Jak to działa. Jeśli masz symbol dziesiętny 1 i dodajesz go do 1, to otrzymujesz symbol dziesiętny 2. Powodem, dla którego nazywam to symbolem, jest to, że możesz użyć dowolnej serii symboli z tabelą odnośników „JEŻELI symbol X (1) jest dodawany do symbolu X (4) NASTĘPNIE symbol wyjściowy X (5) ”. Symbol X (1) może być obrazem kota, a symbol X (4) może być znakiem PROCENTU, ale to nie ma znaczenia. Masz swoje symbole, podstawowy zestaw reguł tego, co się dzieje, a następnie symbole te są łączone (podobnie jak tabliczki mnożenia zapamiętane jako dziecko) i jaki symbol musi powstać w ramach tej operacji. Korzystając z Symbolic Math, możesz dodać nieskończoną liczbę cyfr, nigdy tak naprawdę nie wywołując limitów liczbowych twojego procesora.
Jednym ze sposobów na to w łatwym kodowaniu jest posiadanie każdej reprezentowanej cyfry, z którą chcesz pracować, jako pojedynczej jednostki w tablicy o dużych wymiarach. Jeśli chcesz reprezentować 4096 cyfr dziesiętnych (nie więcej niż 2 cyfry na jednostkę pola), wówczas przydzielasz 2 zestawy lokalizacji tablicy 4096 BYTE. Przechowywanie wartości 1098874 wykorzysta tablicę jako (1) (0) (9) (8) (8) (7) (4). Jeśli dodasz do niego wartość 7756, przekonwertujesz ją na (7) (7) (5) (6), a następnie dodasz. Wynikiem byłoby (1) (0) (9) (15) (15) (12) (10), które następnie odejmowałeś od prawej do lewej, odejmując przesunięcie, aż wszystkie pola cyfr zostaną znormalizowane do wartości (0 do 9). Wartość skrajnie prawa (10) odejmowałaby 10, a wynikowa wartość wynosiłaby zero (0), a to przenosiłoby wartość (1) do następnego lewego pola (12), aby uzyskać (13), która następnie miałaby 10 odejmowane, aby uzyskać do (3).
źródło
`text`
→text
) spowoduje, że będzie on mono-odstępowy, odpowiedni dla fragmentów kodu, nazw funkcji, danych itp. Zawijanie tekstu w podkreślenia lub gwiazdki spowoduje, że będzie on pisany kursywą (_text_
lub*text*
→ tekst ), a podwójne podkreślenia lub podwójne- gwiazdki powodują pogrubienie (__text__
lub**text**
→ tekst ).To, co robisz, łączy kilka zmiennych, a następnie sam kontrolujesz dodawanie i przepełnienie między nimi. W ten sposób możesz mieć dowolną liczbę cyfr. Połącz 10 000 32-bitowych liczb całkowitych, a otrzymasz liczbę 32 000 bitów, jeśli tego potrzebujesz. Nie ma ograniczeń w żadnym języku programowania. Jedynym ograniczeniem jest to, co możesz zrozumieć.
źródło
double
lubBigInteger
.