¿Algún documento que diga exactamente para qué rango de números están diseñados .NET BigIntegers?

12

Estoy jugando con .NET BigInteger y básicamente me pregunto qué número, una respuesta estimada, estaría bien, es el punto de desviación de la curva de (la gráfica de (aumento del tiempo requerido para las operaciones) vs (valor de BigInteger))?

¿o están diseñados sin tal desviación de modo que si graficamos el aumento de tiempo requerido para las operaciones frente al valor de BigInteger de 1 a infinito, tendremos una curva suave en todo momento?

por ejemplo, suponiendo que las matrices están diseñadas con la capacidad de manejar 50 artículos. Esto significa que si tengo 1 elemento, las operaciones son f (1) tiempo. y cuando tengo 2 artículos, las operaciones son f (2) tiempo. Si tengo 50 artículos, las operaciones son f (50) tiempo. pero como está diseñado para manejar solo 50 artículos, las operaciones que se realicen cuando tengamos 51 artículos serán g (51) donde g (51)> f (51).

Si se implementa correctamente, la complejidad de la aritmética BigInteger debería ser una curva suave. Por ejemplo, la complejidad temporal de la multiplicación debe ser O (NM) donde N es el número de dígitos en el primer multiplicando y M es el número de dígitos en el segundo multiplicando. Por supuesto, hay límites prácticos en el sentido de que puede elegir N y M tan grandes que los números no caben en su máquina.

¿Hay alguno / alguien sabe de algún documento que afirme que se implementa como tal?

Pacerier
fuente
3
@Votantes bajos, los votos negativos no significan nada si no puedes dejar un comentario explicando por qué la pregunta no es una buena pregunta. Voté esto porque no veo problemas con él.
The Muffin Man
No voté en contra, pero no estoy seguro de cuál es la pregunta aquí. ¿Desea conocer la complejidad del tiempo de ejecución / memoria de las operaciones en bigints (suma, multiplicación, división, etc.)?
Nikkie
por ejemplo, suponiendo que las matrices están diseñadas con la capacidad de manejar 50 artículos. Esto significa que si tengo 1 elemento y las operaciones son f (1) tiempo. y cuando tengo 2 artículos, las operaciones son f (2) tiempo. si tengo 50 artículos, las operaciones son f (50) tiempo. pero como está diseñado para manejar solo 50 artículos, las operaciones que se realicen cuando tengamos 51 artículos serán g (51) donde g (51)> f (51)
Pacerier del
@Charles E. Grant, sí! esto es de lo que hablo. la pregunta es si hay / ¿alguien sabe de algún documento que afirme que se implementa como tal?
Pacerier
@Paceier He movido mi comentario a mi respuesta, y agregué un enlace a un documento que discute exactamente esto.
Charles E. Grant

Respuestas:

7

Cualquier número que pueda ser más grande que ULong.MaxValue o más pequeño que Long.MinValue debe representarse con BigInteger.

Si NO (Long.MinValue <= X <= ULong.MaxValue) Entonces BigInteger

BigInteger es para cantidades demasiado grandes que las primitivas normales pueden manejar.

Por ejemplo, si su número entero está fuera del rango de Long, probablemente debería usar BigInteger. Sin embargo, estos casos son muy raros, y el uso de estas clases tiene una sobrecarga significativamente mayor que sus contrapartes primitivas.

Por ejemplo, longtiene 64 bits de ancho y puede contener el rango: -9,223,372,036,854,775,808 a 9,223,372,036,854,775,80. ulong puede contener de 0 a 18,446,744,073,709,551,615. Si sus números son más grandes o más pequeños que eso, BigInteger es su única opción

La única vez que los he visto utilizados en una aplicación del mundo real fue una aplicación de diagrama de estrellas.

Vea también: Rangos primitivos en .NET

Malfist
fuente
quiero decir, por supuesto, sé que debemos usar primitivas normales siempre que podamos ... quiero decir, por ejemplo, ¿BigInteger está diseñado para números 100 veces más grandes que ULong.MaxValue o BigInteger está diseñado para números 100k veces más grandes que ULong.MaxValue? Quiero decir que sé que puede soportar 100k veces más grande que ULong.MaxValue, pero ¿está diseñado con este rango en mente o con este rango declarado "requisito fuera de lo común"?
Pacerier
55
No puede representar un número incluso uno mayor que ULong.MaxValue sin usar BigInteger, por lo que es para eso. Cualquier número que pueda ser mayor que ULong.MaxValue debería ser un BigInteger.
Malfist
por supuesto, hay formas de representar números mayores que ULong.MaxValue y sin usar BigInteger. simplemente podría escribir una estructura personalizada que consta de un ULong y un boolean y viola que puedo representar hasta dos veces de ULong.MaxValue
Pacerier
Sí, pero es mucho menos complicado usar BigInteger, y probablemente no sería mucho más rápido, si es que es más rápido, y no sería tan flexible como BigInteger. También podría representar números muy grandes con una matriz de booleanos, pero eso es demasiado complicado.
Malfist
2
@Mavrik, ha cambiado esto a una pregunta completamente diferente a la que respondí.
Malfist
4

En cierto sentido, el objetivo de BigInteger no es tanto el tamaño absoluto como la precisión ilimitada. Los números de coma flotante también pueden ser muy grandes, pero tienen una precisión limitada. BigInteger le permite realizar operaciones aritméticas sin preocuparse por errores de redondeo o desbordamiento. El precio que paga es que es cientos de veces más lento que la aritmética con números enteros ordinarios o números de coma flotante.

Como otros han señalado, ulong puede contener entre 0 y 18,446,744,073,709,551,615, y siempre que permanezca en ese rango puede hacer operaciones aritméticas exactas. Si va incluso 1 más allá de ese rango, obtendrá un desbordamiento, por lo que la respuesta a su pregunta es usar BigInteger si necesita una aritmética exacta y existe la posibilidad de que cualquier resultado intermedio exceda 18,446,744,073,709,551,615.

La mayoría de los problemas en ciencia, ingeniería y finanzas pueden vivir con las aproximaciones forzadas por los números de coma flotante, y no pueden permitirse el costo del tiempo de la aritmética BigInteger. La mayoría de los cálculos comerciales no pueden vivir con las aproximaciones de la aritmética de coma flotante, pero funcionan dentro del rango de 0 a 18,446,744,073,709,551,615, por lo que pueden usar la aritmética ordinaria. BigInteger es necesario cuando se utilizan algoritmos de la teoría de números que incluyen cosas como la criptografía (piense en números primos de 50 dígitos). A veces también se usa en aplicaciones comerciales cuando se necesitan cálculos exactos, la velocidad no es demasiado importante y establecer un sistema de punto decimal fijo adecuado es demasiado problema.

Si se implementa correctamente, la complejidad de la aritmética BigInteger debería ser una curva suave. Por ejemplo, la complejidad temporal de la multiplicación debería ser O (NM) donde N es el número de dígitos en el primer multiplicando y M es el número de dígitos en el segundo multiplicando. Por supuesto, hay límites prácticos en el sentido de que puede elegir N y M tan grandes que los números no caben en su máquina.

Si buscas en Google "Complejidad computacional de biginteger" obtendrás más referencias de las que puedes sacudir. Una que responde directamente a su pregunta es la siguiente: Comparación de dos paquetes aritméticos de precisión arbitraria .

Charles E. Grant
fuente
4

Limite de memoria

BigInteger se basa en la matriz int para el almacenamiento. Suponiendo esto, el límite teórico para el número máximo, que BigInteger es capaz de representar, puede derivarse del tamaño máximo de matriz disponible en .net. Aquí hay un tema SO sobre las matrices: encontrar la cantidad de memoria que puedo asignar para una matriz en C # .

Suponiendo que conocemos el tamaño máximo de matriz, podemos estimar el número máximo, que BigInteger puede representar: (2 ^ 32) ^ max_array_size, donde:

  • 2 ^ 32 - número máximo en la celda de la matriz (int)
  • max_array_size: tamaño máximo permitido de la matriz int que está limitado por un tamaño de objeto de 2 GB

Esto da número con 600 millones de dígitos decimales.

Límite de rendimiento

En cuanto al rendimiento, BigInteger utiliza el algoritmo Karatsuba para la multiplicación y el algoritmo lineal para sumar. La complejidad de la multiplicación es 3 * n ^ 1.585, eso significa que escalará bastante bien incluso para grandes números ( Gráfico de complejidad ), sin embargo, aún puede afectar la penalización del rendimiento dependiendo del tamaño de la RAM y la memoria caché del procesador.

Hasta ahora, dado que el tamaño máximo de número está limitado a 2 GB, en la máquina de descenso no verá una brecha de rendimiento inesperada, pero aún operando en números de 600 millones de dígitos será muy lento.

Valera Kolupaev
fuente
Esta es una información maravillosa, sin embargo, ¿dónde está su fuente de que BigInteger se basa en matrices int?
Pacerier
Acabo de buscar en las fuentes .net usando dotPeek. Parece que el número en sí está almacenado dentro de uint [] _data de la estructura BigInteger.
Valera Kolupaev
* Actualizado con una respuesta más detallada, sin embargo, no puedo encontrar ningún código fuente .net, al que pueda hacer referencia, excepto fragmentos descompilados.
Valera Kolupaev
Me parece que hay un algoritmo de multiplicación estándar en .NET, ya que puede deducirse de ILSpy: Multiplicación .NET BigInteger
Ivan Kochurkin
1

El límite es el tamaño de su memoria (y el tiempo que tiene). Entonces, puedes tener números realmente grandes. Como dijo Kevin, en criptografía uno tiene que multiplicar o exponer números con unos mil dígitos (binarios), y esto es posible sin ningún problema.

Por supuesto, a menudo los algoritmos se vuelven más lentos a medida que los números se hacen más grandes, pero no tanto más lento.

Sin embargo, cuando usa números en el rango de mega dígitos, es posible que desee pensar en otras soluciones, ya que calcular realmente con ellas también se vuelve lento.

Paŭlo Ebermann
fuente
0

Hay algunos usos dentro de la comunidad científica (es decir, la distancia entre las galaxias, el número de átomos en un campo de hierba, etc.)

Dave Wise
fuente
uh no ser grosero ... pero ¿cómo se relaciona esta respuesta con la pregunta?
Pacerier
2
La pregunta, tal como está escrita, parece que estaba buscando un ejemplo del mundo real de por qué sería necesario crear ese tipo de datos.
Dave Wise
una mejor frase sería "¿BigInteger es realmente adecuado para números tan grandes como 10 ^ 30"?
Pacerier
Para esto, mejor usaría doubleo float, de todos modos, no tiene la precisión necesaria.
Paŭlo Ebermann
una mejor frase sería "¿BigInteger es realmente adecuado para números tan grandes como 10 ^ 30 cuando necesitamos la precisión"?
Pacerier
0

Como sugiere la respuesta de kevin cline, BigNumbers se agregaron a las bibliotecas .NET principalmente porque se necesitaban como un bloque de construcción para muchos algoritmos criptográficos modernos (firmas digitales, cifrado de clave pública / privada, etc.). Muchos algoritmos criptográficos modernos implican cálculos sobre valores enteros con tamaños de hasta varios miles de bits. Dado que la clase BigNumber describe una clase bien definida y útil, decidieron hacerla pública (en lugar de mantenerla como un detalle interno de las API criptográficas).

Stephen C. Steel
fuente
Por cierto, ¿dónde está su fuente de que se agregaron BigNumbers a las bibliotecas .NET principalmente porque eran necesarios como un bloque de construcción para muchos algoritmos criptográficos modernos (y, por lo tanto, deberían ser capaces de admitir valores de hasta varios miles de bits)?
Pacerier