¿Cómo manejan los juegos inactivos números tan grandes?

31

Me pregunto cómo los juegos como Tap titans y Cookie Clicker manejan números tan grandes.

Estoy tratando de implementar un juego inactivo, sin embargo, el formato de número más grande admitido por C # es decimal.

Estoy buscando soportar hasta 10 ^ 500; eso tiene que ser punto flotante

¿Cómo podría manejar esto?

PD: debe ser multiplataforma, es decir, PC, Mac, iOS, Android y compatible con Unity

MathHelp
fuente
2
Si no recuerdo mal, tienes acceso al código de Cookie Clicker, así que puedes verificar eso ...
Vaillancourt
¡No, ya había bloqueado Cookie Clicker de mi mente!
Arturo Torres Sánchez
2
He visto la fuente descompilada de TimeClickers , un juego de Unity. Ellos solo usan double. Sin embargo, si hubiera sido yo, habría usado BigInteger .
BlueRaja - Danny Pflughoeft
1
@VioletGiraffe: Estoy de acuerdo, y me gustaría aclarar mis dudas (¿nuestras?) (Posiblemente para ayudar al OP a aclarar la pregunta): ¿Qué es un "juego inactivo" con respecto a la pregunta? de juego un caso especial para grandes números)? ¿A qué tipo de números se refiere " tales números grandes" (resaltar por mí mismo)? ¿ Qué tan grande quieres que sean los números?
O Mapper
siempre puede almacenar un número tan grande en una cadena e implementar fácilmente una función para hacer una suma en la cadena.
dev-masih

Respuestas:

40

Si solo desea almacenar números masivos sin precisión completa, por ejemplo, si va a mostrar 12,567,000,000,000 como 12.567T (billones), puede usar valores estándar flotantes / decimales y mostrar las primeras x cifras significativas, con un sufijo adecuado Me gusta esto. Cuando estás en los octillones, ¿realmente necesitas preocuparte por cada incremento entero individual?

Ross Taylor-Turner
fuente
44
Esta es probablemente la respuesta más sensata en realidad, y estoy bastante seguro de que Cookie Clicker solo usa un flotador estándar en JavaScript, por ejemplo, cuando lo "pirateé" (léase: en mal estado con la consola) y cuando el número llegó a 1e308, saltó a "Infinity" y podría proceder a comprar lo que quisiera XD
Niet the Dark Absol
1
¡Excelente! El hecho de que el texto salte a "Infinito" parece que el desarrollador también estaba codificando defensivamente esta eventualidad. Además, la simplicidad es el rey.
Ross Taylor-Turner
19
@RossTurner: probablemente no hubo codificación para que muestre el texto "Infinito": el infinito es solo un valor que puede tener un flotador y JavaScript sabe cómo mostrarlo, como lo hacen muchos otros idiomas.
Jibb Smart
Los flotantes estándar (precisión doble, 8 bytes) no permitirán representar números de hasta 10 ^ 500 como lo requiere la pregunta original, subirán a ~ 10 ^ 300. Si eso no es suficiente, uno debe usar flotadores de precisión cuádruple que pueden no ser triviales dependiendo del idioma.
Peteris
1
Lo que todo programador debe saber sobre los números de coma flotante
Steve
20

Podría usar algo como BigInteger , que solo está disponible en .net 4.0 si no me equivoco (no es compatible con todas las plataformas de construcción de la unidad).

Sin embargo, hay algunas bibliotecas que intentan llevar esta funcionalidad sin el requisito de .net4.0. Por ejemplo aquí .

Alternativamente, puede usar números más pequeños para representar uno más grande, haciendo un seguimiento del multiplicador. Por ejemplo:

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

Ahora, aunque tenga un valor de 9, si lo combina con su multiplicador, puede representar efectivamente ese 9 como 9 billones (ya sea poniendo "billones" o escribiendo algo que agregará los ceros al final de su valor )

jgallant
fuente
Vale la pena señalar que las clases como el BigIntegeruso de una representación String o Byte [] del número, por lo que en realidad se podría crear su propia clase que simplemente suma y resta dos "números como Strings o Bytes" - ( generalmente este tipo de juego no no lo necesita, pero también podría admitir la multiplicación o división u otras funciones más avanzadas ), pero tendrían que tener en cuenta que siempre hay un límite físico en el que pueden quedarse sin memoria.
DoubleDouble
1
Cada byte multiplica el tamaño de su número por 256. Si se queda sin memoria tratando de representar un número, su número no tenía ningún valor real de todos modos. 256 ^ (2 mil millones) = 2 ^ 8 ^ (2 mil millones) = 2 ^ (16 mil millones) ~ = 10 ^ (5 mil millones) (Wolframalpha se rompió tratando de hacer esa última conversión). Puede especificar volúmenes de Planck individuales en el universo observable utilizando como 150 dígitos (<500 bits).
MichaelS
11

Es probable que necesite escribir su propia clase para usar en Unity, pero no sería particularmente difícil.

Internamente, podría ser una lista de enteros (como a List<int>), con cada elemento en la lista correspondiente a un grupo de 9 dígitos. Cada número entero tendría un rango de 0 a 999 999 999. Un número entero puede admitir un poco más de 2 mil millones, y duplicarlo si no está firmado, pero querrá tener cada desbordamiento de "dígito" 1 000 000 000, porque también querrá para poder convertir fácilmente su número grande en una cadena para mostrar. Es más fácil concatenar lo que ya son dígitos decimales ( return group[i].ToString() + group[i-1].ToString() and so on) que descubrir cómo mostrar la suma de grupos que están fuera del rango de cualquier tipo de datos regular.

Entonces, el primer int en su lista representaría 1s. El siguiente sería el número de miles de millones. El siguiente, el número de cuatrillones, y así sucesivamente.

La suma y la resta funcionarían igual que la suma y resta de lápiz y papel, donde debe observar el desbordamiento y llevarlo al siguiente "dígito", pero en lugar de dígitos con un rango de 0-9, sus dígitos van desde 0 a 999999999.

Jibb Smart
fuente
10

Para manejar números grandes, miraría lo que creo que es un buen ejemplo como Tower of Hero . Esquina superior izquierda:

1

2
(fuente: mzstatic.com )

Sin entrar en el juego, la forma en que maneja los números es relativamente simple: ves dos cubos de números. A medida que asciendes en la torre y haces más "oro", los dos cubos simplemente representan números más grandes.

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

Una vez que el juego pasa T, se mueve a a, b, c ... z, aa, ab, ...

56aa608z

Al hacerlo de esta manera, todavía te permite saber cuánto oro has "ganado" ... sin atascar el juego en detalles.

¿Realmente te importan Millones cuando tu número supera los Trillones?

¿Mantiene el número en Int, Big Int, Float, Double, Decimal, ...? Matriz personalizada? Cuando manejas números de una manera tan "difusa", no creo que importe ...

Todo lo que probablemente importa son las partes más importantes, en este caso, los primeros 6 ... Después de eso, tal vez los próximos 3 o 6, ya que ganar unos cientos de K puede pasar a Millones, pero hay un punto en el que ganar unos pocos cientos de K no te afectarán cuando golpees T ... mucho menos aa y más allá.

Su millaje variará (dependiendo de lo que quiera / necesite) ... Solo pensé que pondría mi 2c en lo que creo que es un buen / simple ejemplo.

Editar:

Más ideas sobre cómo implementar el sistema de numeración: tendría un número con 3 partes significativas: XXXX.YYY (...) xZZZ.

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

Por lo tanto, 120.365x1 sería 120k365 ... 120.365x2 sería 120M365K ... etc. Presione los 4 primeros (1200.365x2), luego gire los números 1.200365 (...) x3. Bam Tienes 1B200M.

XY encajaría fácilmente en un decimal o flotante ... con Z sentado a su lado como int / unsigned int.

Con un flotador, podrá mantener una cantidad considerable, pero cada vez menos importante, de dígitos después del punto.

Z representaría fácilmente un bloque de números fácilmente comprensible:

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

Y una manera fácil de manejar grandes números es simplemente tener más de un valor INTEGER y luego TRANSPORTAR cualquier desbordamiento. Si tiene un valor INT de 16 bits (0 a 65535) y desea tener más que eso, use dos valores INT de 16 bits en una fila. Piense en ello como tener un valor BYTE (0 a 255) pero solo usarlo hasta 99 dígitos de valor. Una vez que llegue a 100, luego gírelo al siguiente valor BYTE más alto para todos los dígitos que considere útiles. Con las computadoras GHZ actuales, incluso una codificación descuidada como esa está bien.

Por supuesto, hay una alternativa que es un poco más rápida.
Si sumas 18 repetidamente a un número, es más rápido restar simplemente 2 y sumar 20. 18, 36, 54, 72, 90, 108, ... 18 = 20 + (- 2).
Funciona en binario también. (Los mismos valores decimales en binario) 10010, 100100, 110110, 1001000
DEC (18) = BIN (10010)
Excepto para un análisis binario más fácil, debe pensar en 18 = 16 + 2
DEC (16 + 2) = BIN (10000 + 00010). Si el valor era 15, piense en ello como sumando 16 en binario y restando 1 (10000-00001).

De esta manera, puede mantener los fragmentos de números en límites manejables por valor.
Si está utilizando el método de codificación descuidada de limitar un valor INT básico de 16 bits (0 a 65535) a un límite decimal de 4 dígitos (0 a 9999), entonces todo lo que tiene que hacer es cuando el valor excede el límite de 9999, reste 9999 y llévelo al siguiente fragmento de valor (ya que básicamente está haciendo "sumas y subs" con números versus un cálculo binario real).

Idealmente, solo usarías MATEMÁTICA SIMBÓLICA que aprendiste en la escuela primaria. Como funciona esto. Si tiene el símbolo decimal de 1 y lo agrega a 1, entonces obtiene el símbolo decimal de 2. La razón por la que llamo a esto un símbolo es que podría usar cualquier serie de símbolos con una tabla de búsqueda de "símbolo IF X (1) se agrega al símbolo X (4) ENTONCES el símbolo de salida X (5) ". El símbolo X (1) podría ser una imagen de un gato y el símbolo X (4) podría ser el signo de PORCENTAJE, pero no importa. Tienes tus símbolos, un libro de reglas básico de lo que sucede, luego esos símbolos se combinan (algo así como las tablas de multiplicar que memorizaste cuando eras niño) y qué símbolo debe resultar como parte de esa operación. Con el uso de Symbolic Math, puede agregar un número infinito de dígitos sin tener que invocar los límites numéricos de su procesador.

Una forma de hacer esto en una codificación fácil es tener cada dígito representado con el que desea trabajar como una sola unidad en una matriz de dimensiones grandes. Si desea representar 4096 dígitos decimales (que no excedan 2 dígitos por caja de unidad), entonces asigne 2 conjuntos de ubicaciones de matriz 4096 BYTE. El almacenamiento del valor de 1098874 utilizaría la matriz como (1) (0) (9) (8) (8) (7) (4). Si le agregaste el valor de 7756, lo convertirías en (7) (7) (5) (6) y luego lo sumarías. El resultado sería (1) (0) (9) (15) (15) (12) (10) que luego restaría de derecha a izquierda con desplazamiento hasta que todos los cuadros de dígitos se normalizaron para ser el valor de (0 a 9) El valor más a la derecha (10) tendría 10 restados y el valor resultante sería cero (0) y eso llevaría el valor (1) al cuadro siguiente-izquierdo de (12) para convertirlo en (13) que luego tendría 10 restado para convertirlo en (3).

Gridlock
fuente
77
-1 por DEMASIADO
GRITAR
55
Hola @Gridlock, acabo de notar que eres un usuario completamente nuevo, bienvenido. Debo aclarar que mi voto negativo no es permanente; pretende ser una crítica constructiva. La respuesta que ha proporcionado tiene un valor, y estaré más que feliz de cambiarla a un voto positivo una vez que haya realizado la corrección que solicito. Además, tenga en cuenta que SE no es un foro; una buena respuesta no se lee y luego se olvida, sino que paga dividendos con el tiempo. Revisar sus respuestas aquí y allá ayuda a la comunidad y a su representante. Espero no haberte asustado; de nuevo, bienvenido y espero que uses mi consejo
Slipp D. Thompson
1
La otra sugerencia que ofreceré es usar un formato básico de Markdown en lugar de mayúsculas. Ajustar el texto en comillas ( `text`text) lo hará en un espacio sencillo, apropiado para fragmentos de código, nombres de funciones, datos, etc. El texto en minúsculas o asteriscos lo pondrá en cursiva ( _text_o *text*texto ), y doble guión bajo o doble- los asteriscos lo pondrán en negrita ( __text__o **text**texto ).
Slipp D. Thompson
0

Lo que haces es combinar varias variables, y luego controlas la adición y el desbordamiento entre ellas. Puede tener cualquier número de dígitos de esa manera. Combine 10,000 enteros de 32 bits y obtendrá un número con 32,000 bits, si eso es lo que necesita. No hay límite en ningún lenguaje de programación. El único límite es lo que eres capaz de resolver.

Franco
fuente
Para aquellos que dieron votos negativos, ¿podrían explicar por qué? Incluso si esta no es una solución popular, o una que requiere cero esfuerzo, sigue siendo una solución, y una que podría permitirle hacer lo mismo incluso en idiomas / plataformas que no son compatibles doubleo no BigInteger.
TomTsagk