C# - O Tipo de dados BigInteger


Se você precisa trabalhar com números inteiros muito absurdamente grandes, os tipos de dados Integer e Long talvez não suportem o intervalo numérico com o qual você precisa tratar.

Felizmente para esses cenários, a partir da versão 4.0 do NET Framework, temos disponível a struct BigInteger.

O tipo de dados Long trata números inteiros(8 byte) de 64 bit cujo valor varia de -9.223.372.036.854.775.808 até de 9.223.372.036.854.775.807 (9.2... E+18).
  • O tipo correspondente no .NET Framework é a estrutura System.Int64;
  • Você pode converter um tipo de dados Long para Decimal, Single ou Double sem ocorrer em um OverflowException;

O tipo de dados Integer armazena inteiros de 32 bits (4-byte) com sinal que variam em valor de -2,147,483,648 a 2,147,483,647.

  • O tipo de dados Integer proporciona um desempenho ideal em um processador de 32 bits. Os outros tipos integrais são mais lentos para carregar e armazenar na memória;
  • O tipo correspondente no .NET Framework é a estrutura System.Int32;
  • Você pode converter um tipo de dados Integer para Long, Decimal, Single ou Double sem ocorrer em um OverflowException;

O tipo BigInteger é um tipo imutável presente no namespace System.Numerics que representa um inteiro arbitrariamente grande cujo valor, em teoria não possui limites superiores ou inferiores.

A imutabilidade de BigInteger : Como o tipo de dados BigInteger é imutável você deve tomar cuidado ao realizar certas operações que podem afetar o desempenho da sua aplicação.

Assim o código abaixo :

BigInteger a = 1;
a += 1;

Irá resultar na criação de um segundo objeto BigInteger; o que é totalmente transparente para você mas pode afetar seu desempenho.

Assim, para usar esse recurso você terá que incluir uma referência ao assembly System.Numerics no seu projeto.



Os membros do tipo BigInteger são muito semelhantes dos outros tipos integrais (como o Byte, Int16, Int32, Int64, SByte, UInt16, UInt32, e o UInt64). Esse tipo difere dos outros tipos integrais na .NET Framework que possuem um intervalo indicado pelas suas propriedades MinValue e MaxValue.

Como o tipo BigInteger é imutável, e, como não há limite superiores ou inferiores para seus valores, ele possui um exeção do tipo OutOfMemoryException que é gerada quando uma operação que envolver um biginteger fizer com que o valor BigInteger cresça demais.

Para trabalhar com um BigInteger você pode :

1- Criar uma instância de tipo usando a palavra-chave new fornecendo qualquer valor integral ou de ponto flutuante como um parâmetro para o construtor BibInteger.

using System;
using System.Numerics;
using static System.Console;
namespace CShp_BigInteger
{
    class Program
    {
        static void Main(string[] args)
        {
            BigInteger bigInt_Double = new BigInteger(179032.6541);
            WriteLine(bigInt_Double);
            BigInteger bigInt_Int64 = new BigInteger(934157136952);
            WriteLine(bigInt_Int64);
            ReadLine();
        }
    }
}

2-  Você pode declarar uma variável BigInteger e atribuir um valor, assim como você faria com qualquer tipo numérico, desde que esse valor seja um tipo integral. O exemplo a seguir usa a atribuição para criar um valor BigInteger de um Int64.

using System;
using System.Numerics;
using static System.Console;
namespace CShp_BigInteger
{
    class Program
    {
        static void Main(string[] args)
        {
            long valor_Long = 6315489358112;
            BigInteger atribuido_Long = valor_Long;
            WriteLine(atribuido_Long);
            ReadLine();
        }
    }
}

Para fazer a conversão de uma representação string de um número para um BigInteger podemos usar os métodos Parse e TryParse:

using System;
using System.Numerics;
using static System.Console;
namespace CShp_BigInteger
{
    class Program
    {
        static void Main(string[] args)
        {
            string string_Positiva = "91389681247993671255432112000000";
            string string_Negativa = "-90315837410896312071002088037140000";
            BigInteger positivo_BigInt = 0;
            BigInteger negativo_BigInt = 0;
            try
            {
                positivo_BigInt = BigInteger.Parse(string_Positiva);
                WriteLine(positivo_BigInt);
            }
            catch (FormatException)
            {
                WriteLine($"Não foi possível converter a string '{string_Positiva}' BigInteger");
            }
            if (BigInteger.TryParse(string_Negativa, out negativo_BigInt))
                WriteLine(negativo_BigInt);
            else
                WriteLine("Não foi possível converter a string '{string_Negativa}'  o BigInteger");
            ReadLine();
        }
    }
}

O tipo BigInteger sobrecarrega os operadores numéricos padrão para que você possa realizar operações matemáticas básicas, como adição, subtração, divisão, multiplicação, subtração, negação e negação de unário.

Você também pode usar os operadores numéricos padrão para comparar dois valores BigInteger entre si.

Para idiomas que não oferecem suporte a operadores personalizados, a estrutura BigInteger também fornece métodos equivalentes para realizar operações matemáticas.(Ex: Add, Divide, Multiply, Negate, Subtract e muitas outras)

O BigInteger possui muitos métodos estáticos, tais como o Parse(), TryParse(), e ToString() (que também suporta o formato hexadecimal) encontrados em outros tipos de números inteiros, bem como ajudantes matemáticos, tais como Pow(), log(), Log10(), e outros.

Para mostrar a força e o tamanho de um BigInteger vamos criar uma aplicação usando o VS 2017 Community Edition do tipo Windows Forms com o nome WF_BigInteger;

No formulário padrão Form1.cs vamos incluir alguns controles Label, TextBox e Button e definir o leiaute conforme a figura abaixo:

Após isso no menu Project clique em Add Reference e na aba .NET selecione o item System.Numerics e clique em OK;

O código do formulário acima pode ser visto a seguir:

using System;
using System.Numerics;
using System.Windows.Forms;
namespace WF_BigInteger
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private int N1;
        private BigInteger N2;
        private BigInteger N3;
        private BigInteger N4;
        private BigInteger N5;
        private BigInteger N6;
        private void Form1_Load(object sender, EventArgs e)
        {
            N1 = UInt16.MaxValue;
            N2 = UInt32.MaxValue;
            N3 = UInt64.MaxValue;
            txtNum1.Text = N1.ToString();
            txtNum2.Text = N2.ToString();
            txtNum3.Text = N3.ToString();
        }
        private void btnCalcular_Click(object sender, EventArgs e)
        {
            try
            {
                N4 = N3 + N3;
                N5 = N3 * N3;
                N6 = BigInteger.Pow(N3, 999);

                txtNum4.Text = N4.ToString();
                txtNum5.Text = N5.ToString();
                txtNum6.Text = N6.ToString();
            }
            catch (OutOfMemoryException memex)
            {
                MessageBox.Show(" Erro : " + memex.Message);
            }
            catch (OverflowException ovex)
            {
                MessageBox.Show(" Erro : " + ovex.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(" Erro : " + ex.Message);
            }
        }
    }
}

Executando o projeto teremos o seguinte resultado:

Considerações sobre o código:

Observe o valor obtido na operação BigInteger.Pow(N3, 999) que eleva o número 18446744073709551615 a potência 999.

Realmente é um número integral muuuuuuuuuuuuuuuuuuito grande.

Note também que eu estou tratando as exceções : OutOfMemoryException e OverflowException antes do tratamento geral Exception.

Pegue o projeto completo aqui: CShp_BigInteger.zip

"E não temais os que matam o corpo e não podem matar a alma; temei antes aquele que pode fazer perecer no inferno a alma e o corpo."
Mateus 10:28

Referências:


José Carlos Macoratti