¿Cuál es el límite del tipo de valor BigInteger en C #?

Como se describe en MSDN BigInteger es:

Un tipo inmutable que representa un entero arbitrariamente grande cuyo valor en teoría no tiene límites superiores ni inferiores.

Como puedo ver, BigInteger es un ValueType , que yo sepa, un ValueType debe tener un tamaño máximo de 16 bytes .

MSDN va más allá diciendo:

se puede lanzar una excepción OutOfMemoryException para cualquier operación que haga que un valor de BigInteger crezca demasiado.

y más :

Aunque este proceso es transparente para la persona que llama, incurre en una penalización de rendimiento. En algunos casos, especialmente cuando se realizan operaciones repetidas en un bucle en valores BigInteger muy grandes

¿Cómo podría almacenar valores tan grandes, tan grandes como double.MaxValue + double.MaxValue ? Me dijeron que tiene objetos de tipo de ReferenceType en su interior, pero todo lo que puedo encontrar aquí en su definición en VisualStudio es ValueTypes.

¿Cuál es su límite real? E incluso si no tiene uno, ¿cómo puede “como tipo de valor” gestionar almacenar toda esa cantidad de datos?

Como puedo ver, BigInteger es un ValueType, por mucho que yo sepa, un ValueType debe tener un tamaño máximo de 16 bytes.

No, eso no es verdad. Es un límite convencional , pero es completamente factible que un tipo de valor tome más que eso. Por ejemplo:

 public struct Foo { private readonly int a, b, c, d, e; // Look ma, 20 bytes! } 

Sin embargo, sospecho que BigInteger realidad incluye una referencia a una matriz de bytes:

 public struct BigInteger { private readonly byte[] data; // Some other fields... } 

( La respuesta del musulmán Ben Dhaou muestra una implementación actual utilizando int y uint[] , pero, por supuesto, los detalles de esto se ocultan intencionalmente).

Por lo tanto, el valor de un BigInteger aún puede ser pequeño, pero puede referirse a una gran parte de la memoria, y si no hay suficiente memoria para asignar lo que se requiere cuando realiza alguna operación, obtendrá una excepción.

¿Cómo podría almacenar valores tan grandes, tan grandes como double.MaxValue + double.MaxValue?

Bueno, BigInteger es para enteros , por lo que no me gustaría usarlo para nada que tenga que ver con el double … pero, fundamentalmente, las limitaciones estarán en torno a la cantidad de memoria que tenga y el tamaño de la matriz que el CLR puede manejar. con. En realidad, estarías hablando de números enormes antes de llegar al límite para cualquier número específico, pero si tienes millones de números más pequeños, eso obviamente también tiene grandes requisitos de memoria.

Como confirmación de la respuesta de Jon Skeet, busqué el código fuente de BigInteger . En realidad contiene dos propiedades internas de la siguiente manera:

 internal int _sign; internal uint[] _bits; 

_bits es usado por casi todos los métodos privados / públicos dentro de la clase que se usan para leer / escribir los datos reales.

_sign se utiliza para mantener el signo de BigInteger .

Los métodos privados son extensivamente utilizando operadores binarios y cálculos. Aquí hay una pequeña lista de constantes utilizadas en la clase que podrían reflejar un poco los límites:

 private const int knMaskHighBit = -2147483648; private const uint kuMaskHighBit = 2147483648U; private const int kcbitUint = 32; private const int kcbitUlong = 64; private const int DecimalScaleFactorMask = 16711680; private const int DecimalSignMask = -2147483648; 

PD: Debería haber comentado sobre la respuesta de JS, pero un comentario es demasiado breve. Para ver el código fuente, descárguelo o descompile System.Numerics.dll .