In che modo i giochi inattivi gestiscono numeri così grandi?


31

Mi chiedo solo come giochi come Tap titans e Cookie Clicker gestiscono numeri così grandi.

Sto cercando di implementare un gioco inattivo, tuttavia il formato numerico più grande supportato da C # è decimale.

Sto cercando di supportare fino a 10 ^ 500; che deve essere in virgola mobile

Come potrei gestirlo?

PS deve essere multipiattaforma, cioè PC, Mac, iOS, Android e compatibile con Unity


2
Se ricordo bene, hai accesso al codice di Cookie Clicker, quindi puoi semplicemente verificare che ...
Vaillancourt

No, avevo già bloccato Cookie Clicker dalla mia mente!
Arturo Torres Sánchez,

2
Ho esaminato la fonte decompilata di TimeClickers , un gioco Unity. Usano solo double. Se fossi stato io, avrei usato BigInteger , comunque.
BlueRaja - Danny Pflughoeft,

1
@VioletGiraffe: sono abbastanza d'accordo, e vorrei rendere concreti i miei (nostri?) Dubbi (per aiutare eventualmente l'OP a chiarire la domanda): cos'è un "gioco inattivo" rispetto alla domanda (che rende questo tipo di gioco un caso speciale per grandi numeri)? A quali tipi di numeri si riferiscono "numeri così grandi" (evidenziati da me stesso)? Quanto vuoi che siano i numeri?
OR Mapper

puoi sempre memorizzare un numero così grande in una stringa e implementare facilmente una funzione per fare la somma sulla stringa.
dev-masih,

Risposte:


40

Se vuoi solo memorizzare numeri enormi senza completa accuratezza, ad esempio se mostrerai 12.567.000.000.000 come 12.567 T (trilioni), potresti semplicemente usare valori float / decimali standard e mostrare i primi x numeri significativi, con un suffisso adatto come questo. Quando sei negli ottilioni, hai davvero bisogno di preoccuparti di ogni singolo incremento intero?


4
Questa è probabilmente la risposta più sensata in realtà, e sono abbastanza sicuro che Cookie Clicker usa solo un float standard in JavaScript - caso in cui quando l'ho "hackerato" (leggi: incasinato con la console) e quando il numero ha raggiunto 1e308 è saltato su "Infinito" e potrei procedere con l'acquisto di tutto ciò che desideravo XD
Niet the Dark Absol

1
Grande! Il fatto che il testo passi a "Infinito" sembra che lo sviluppatore stia codificando in modo difensivo anche questa eventualità. Inoltre, la semplicità è re.
Ross Taylor-Turner,

19
@RossTurner - Probabilmente non era coinvolto alcun codice nel fatto che mostrasse il testo "Infinity" - l'infinito è solo un valore che un float può avere e JavaScript sa come visualizzarlo, come fanno molte altre lingue.
Jibb Smart,

I float standard (doppia precisione, 8 byte) non consentiranno di rappresentare numeri fino a 10 ^ 500 come richiesto dalla domanda originale, saliranno a ~ 10 ^ 300. Se ciò non bastasse, si dovrebbero usare galleggianti di precisione quadrupli che potrebbero non essere banali a seconda della lingua.
Peteris,

1
Ciò che ogni programmatore dovrebbe sapere sui numeri in virgola mobile
Steve

20

Potresti usare qualcosa come BigInteger , che è disponibile in .net 4.0 solo se non sbaglio (non supportato da tutte le piattaforme di build di unità).

Ci sono alcune librerie che tentano di portare questa funzionalità senza il requisito di .net4.0. Per esempio qui .

In alternativa, è possibile utilizzare numeri più piccoli per rappresentarne uno più grande, tenendo traccia del moltiplicatore. Per esempio:

double value = 9;
enum Multiplier {
   Hundred,
   Thousand,
   Million,
   Billion,
   Trillion
}

Ora, anche se hai un valore di 9, se lo accoppi al tuo moltiplicatore, puoi effettivamente rappresentare quel 9 come 9 trilioni (inserendo "trilioni" o scrivendo qualcosa che aggiungerà gli zeri alla fine del tuo valore ).


Vale la pena notare che classi come BigIntegerusano una rappresentazione String o Byte [] del numero - quindi in effetti si potrebbe creare la propria classe che aggiunge e sottrae solo due "numeri come String o Byte" - (di solito questo tipo di gioco non lo fa non è necessario, ma potresti supportare la moltiplicazione o la divisione o anche altre funzioni più avanzate ), ma dovrebbero tenere a mente che c'è sempre un limite fisico in cui potrebbero esaurire la memoria.
DoubleDouble

1
Ogni byte moltiplica la dimensione del tuo numero per 256. Se esaurisci la memoria nel tentativo di rappresentare un numero, il tuo numero non aveva comunque alcun valore reale. 256 ^ (2 miliardi) = 2 ^ 8 ^ (2 miliardi) = 2 ^ (16 miliardi) ~ = 10 ^ (5 miliardi) (wolframalpha ha tentato di effettuare l'ultima conversione). È possibile specificare singoli volumi Planck nell'universo osservabile usando come 150 cifre (<500 bit).
MichaelS,

11

Probabilmente avresti bisogno di scrivere la tua classe per l'utilizzo in Unity, ma non sarebbe particolarmente difficile.

Internamente, potrebbe essere un elenco di numeri interi (come a List<int>), con ciascun elemento nell'elenco corrispondente a un gruppo di 9 cifre. Ogni numero intero dovrebbe avere un intervallo compreso tra 0 e 999 999 999. Un numero intero può supportare poco più di 2 miliardi e raddoppiarlo se non è firmato, ma ti consigliamo di avere ogni "overflow" in eccesso 1 000 000 000, perché vorrai anche per poter convertire facilmente il tuo grande numero in una stringa per la visualizzazione. È più facile concatenare quelle che sono già cifre decimali ( return group[i].ToString() + group[i-1].ToString() and so on) piuttosto che capire come visualizzare la somma dei gruppi al di fuori dell'intervallo di qualsiasi tipo di dati normale.

Quindi, il primo int nella tua lista rappresenterebbe 1s. Il prossimo sarebbe il numero di miliardi. Il prossimo, il numero di quadrilioni e così via.

L'aggiunta e la sottrazione funzionerebbero esattamente come l'aggiunta e la sottrazione di carta e penna, in cui è necessario controllare il trabocco e trasferirlo alla "cifra" successiva, ma invece di cifre con un intervallo di 0-9, le cifre vanno da Da 0 a 999 999 999.


10

Per la gestione di grandi numeri, darei un'occhiata a quello che penso sia un buon esempio come Tower of Hero . Angolo in alto a sinistra:

1

2
(fonte: mzstatic.com )

Senza entrare nel gameplay, il modo in cui gestisce i numeri è relativamente semplice: vedi due secchi di numeri. Man mano che sali nella torre e guadagni più "oro", i due secchi rappresentano semplicemente numeri più grandi.

120 
120M320K - 120 Million
120B631M - 120 Billion
120T134B - 120 Trillion

Una volta che il gioco passa T, si sposta in a, b, c ... z, aa, ab, ...

56aa608z

In questo modo, ti consente ancora di sapere quanto oro hai "guadagnato" ... pur non impantanando il gioco nei dettagli.

Ti importa davvero di milioni quando il tuo numero è passato trilioni?

Mantiene il numero in Int, Big Int, Float, Double, Decimal, ...? Matrice personalizzata? Quando gestisci i numeri in un modo così "sfocato", non penso che importi ...

Tutto ciò che probabilmente conta sono le parti più significative - in questo caso, le prime 6 ... Dopodiché, FORSE i successivi 3 o 6 - poiché guadagnare qualche centinaio di K può passare a milioni - ma c'è un punto in cui guadagnare alcune centinaia di K non ti influenzeranno quando premi T ... molto meno aa e oltre.

Il tuo chilometraggio varierà (a seconda di ciò che vuoi / di cui hai bisogno) ... Ho pensato di mettere il mio 2c su quello che penso sia un buon / semplice esempio.

Modificare:

Ulteriori riflessioni su come implementare il sistema di numerazione: avrei un numero con 3 parti significative: XXXX.YYY (...) xZZZ.

X is the most significant digits, 
Y trailing 
Z the multiplier (multiple of 3).

Quindi 120.365x1 sarebbe 120k365 ... 120.365x2 sarebbe 120M365K ... ecc. Premi il 4 iniziale (1200.365x2), quindi ruota solo i numeri 1.200365 (...) x3. Bam. Hai 1B200M.

XY si adatterebbe facilmente in un decimale o Float ... con Z seduto accanto come int / unsigned int.

Con un float, sarai in grado di mantenere un numero considerevole, ma sempre meno importante, di cifre dopo il punto.

Z rappresenterebbe facilmente un blocco di numeri facilmente comprensibile:

K = 1
M = 2
B = 3
T = 4
a = 5 
...
z = 31 (I may be off on this)
aa = 32
...
az = 58
ba = 59
...
...

1

E un modo semplice per gestire grandi numeri è semplicemente quello di avere più di un valore INTEGER, quindi TRASFERIRE qualsiasi overflow. Se si dispone di un valore INT a 16 bit (da 0 a 65535) e si desidera averne di più, utilizzare due valori INT a 16 bit in una riga. Pensalo come avere un valore BYTE (da 0 a 255) ma utilizzandolo solo fino a 99 cifre di valore. Una volta che colpisce 100, quindi passa al valore BYTE successivo più alto per tutte le cifre che ritieni utili. Con i computer GHZ di oggi, anche una programmazione così sciatta va bene.

Certo, c'è un'alternativa che è un po 'più veloce.
Se aggiungi 18 ripetutamente a un numero, è più veloce semplicemente sottrarre 2 e aggiungere 20. 18, 36, 54, 72, 90, 108, ... 18 = 20 + (- 2).
Funziona anche in binario. (Stessi valori decimali in binario) 10010, 100100, 110110, 1001000
DEC (18) = BIN (10010)
Ad eccezione dell'analisi binaria più semplice, è necessario pensare a 18 = 16 + 2
DEC (16 + 2) = BIN (10000 + 00010). Se il valore era 15, allora pensalo come aggiungere 16 in binario e sottrarre 1 (10000-00001).

In questo modo, è possibile mantenere i blocchi numerici a limiti gestibili per valore.
Se stai utilizzando il metodo di codifica sciatta per limitare un valore INT di base a 16 bit (da 0 a 65535) a un limite decimale di 4 cifre (da 0 a 9999), tutto ciò che devi fare è quando il valore supera il limite di 9999, sottrai 9999 da esso e portalo al prossimo blocco di valore (dato che stai praticamente facendo "add & subs" con numeri contro un vero calcolo binario).

Idealmente, useresti solo MATEMATICA SIMBOLICA che hai imparato alle elementari. Come funziona. Se hai il simbolo decimale di 1 e lo aggiungi a 1, ottieni il simbolo decimale di 2. Il motivo per cui lo chiamo un simbolo è che puoi utilizzare qualsiasi serie di simboli con una tabella di ricerca di "SE simbolo X (1) viene aggiunto al simbolo X (4) ALLORA simbolo di uscita X (5) ". Il simbolo X (1) potrebbe essere l'immagine di un gatto e il simbolo X (4) potrebbe essere il segno PERCENTE, ma non importa. Hai i tuoi simboli, un regolamento di base di ciò che accade, quindi quei simboli vengono combinati (un po 'come le tabelle di moltiplicazione che hai memorizzato da bambino) e quale simbolo deve risultare come parte di quell'operazione. Con l'utilizzo di Symbolic Math puoi aggiungere un numero infinito di cifre senza mai chiamare i limiti numerici del tuo processore.

Un modo per farlo con la semplice codifica è avere ciascuna cifra rappresentata con cui si desidera lavorare come singola unità in un array di grandi dimensioni. Se si desidera rappresentare 4096 cifre decimali (non superiori a 2 cifre per casella unità), quindi si allocano 2 serie di 4096 posizioni di array BYTE. La memorizzazione del valore di 1098874 utilizza l'array come (1) (0) (9) (8) (8) (7) (4). Se aggiungessi il valore di 7756, lo convertiresti in (7) (7) (5) (6) e poi aggiungeresti. Il risultato sarebbe (1) (0) (9) (15) (15) (12) (10) che si sottrarrebbe quindi da destra a sinistra fino a quando tutte le caselle delle cifre fossero normalizzate per essere il valore di (da 0 a 9). Il valore più a destra (10) avrebbe 10 sottratto e il valore risultante sarebbe zero (0) e che porterebbe il valore (1) nella casella successiva a sinistra di (12) per renderlo (13) che quindi avrebbe 10 sottratto per trasformarlo in (3).


7
-1 per TOO MOLTO YELLING
Slipp D. Thompson,

5
Ehi @Gridlock, ho appena notato che sei un utente completamente nuovo, benvenuto. Dovrei chiarire che il mio voto negativo non è permanente; è inteso come critica costruttiva. C'è un valore per la risposta che hai fornito e sarò più che felice di cambiarlo in un voto dopo aver apportato la correzione che sto richiedendo. Inoltre, tieni presente che SE non è un forum; una buona risposta non viene letta e poi dimenticata, ma paga dividendi rep nel tempo. Revisionare le tue risposte qui e là aiuta la community e il tuo rappresentante. Spero di non averti spaventato; di nuovo, benvenuto e spero che utilizzerai il mio consiglio.
Slipp D. Thompson,

1
L'altro suggerimento che offrirò è di usare una formattazione di Markdown di base invece di maiuscole. L'avvolgimento del testo nei backtick ( `text`text) lo renderà mono-spaziato, appropriato per blocchi di codice, nomi di funzioni, dati, ecc. L'avvolgimento del testo in caratteri di sottolineatura o asterischi lo renderà corsivo ( _text_o *text*testo ) e doppio trattino basso o doppio- gli asterischi lo renderanno grassetto ( __text__o **text**testo ).
Slipp D. Thompson,

0

Quello che fai è avere diverse variabili combinate, e poi controlli tu stesso l'aggiunta e il trabocco. Puoi avere un numero qualsiasi di cifre in questo modo. Combina 10.000 numeri interi a 32 bit e hai un numero con 32.000 bit, se è quello che ti serve. Non c'è limite in nessun linguaggio di programmazione. L'unico limite è quello che sei in grado di capire.


Per quelli che hanno dato voti negativi, potresti spiegare perché? Anche se questa non è una soluzione popolare, o che richiede uno sforzo zero, è comunque una soluzione, e quella che potrebbe permetterti di fare lo stesso anche su lingue / piattaforme che non supportano doubleo BigInteger.
TomTsagk
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.