qualquer documento que diga exatamente para qual intervalo de números o .NET BigIntegers foi desenvolvido?


12

Estou brincando com o .NET BigInteger e, basicamente, estou imaginando qual número - uma resposta estimada seria boa - é o ponto de desvio da curva de (o gráfico de (aumento do tempo necessário para operações) vs (valor de BigInteger))?

ou eles são projetados sem esse desvio, de modo que, se traçarmos o aumento do tempo necessário para operações versus o valor do BigInteger de 1 até o infinito, teremos uma curva suave por todo o caminho?

por exemplo, supondo que matrizes sejam projetadas com capacidade de lidar com 50 itens. isso significa que se eu tiver 1 item, as operações serão f (1) time. e quando eu tiver 2 itens, as operações serão f (2) time. se eu tiver 50 itens, as operações são f (50). mas como ele foi projetado para lidar apenas com 50 itens, as operações realizadas quando tivermos 51 itens serão g (51) onde g (51)> f (51).

Se implementada corretamente, a complexidade da aritmética do BigInteger deve ser uma curva suave. Por exemplo, a complexidade temporal da multiplicação deve ser O (NM), onde N é o número de dígitos no primeiro multiplicando e M é o número de dígitos no segundo multiplicando. É claro que existem limites práticos em que você pode escolher N e M tão grandes que os números não cabem em sua máquina.

Existe / alguém conhece algum documento alegando que ele foi implementado como tal?


3
@Down eleitores, votos negativos não significam nada se você não puder deixar um comentário explicando por que a pergunta não é uma boa pergunta. Eu votei positivo porque não vejo problemas.
The Muffin Man

Não diminuí o voto, mas não tenho certeza de qual é a questão aqui. Deseja conhecer a complexidade do tempo de execução / memória das operações em bigints (adição, multiplicação, divisão etc.)?
Nikie

por exemplo, supondo que matrizes sejam projetadas com capacidade de lidar com 50 itens. isso significa que se eu tiver 1 item e as operações forem f (1) time. e quando eu tiver 2 itens, as operações serão f (2) time. se eu tiver 50 itens, as operações são f (50) time. mas desde que ele é projetado para lidar com 50 itens somente, as operações feitas quando temos 51 itens serão g (51), onde g (51)> f (51)
Pacerier

@ Charles E. Grant sim! é disso que eu estou falando. pergunta: existe / alguém conhece algum documento alegando que ele foi implementado como tal?
Pacerier 2/08

@Paceier Mudei meu comentário para minha resposta e adicionei um link para um documento discutindo exatamente isso.
Charles E. Grant

Respostas:


7

Qualquer número que possa ser maior que ULong.MaxValue ou menor que Long.MinValue deve ser representado usando BigInteger.

Se NÃO (Long.MinValue <= X <= ULong.MaxValue), então BigInteger

O BigInteger é para números muito grandes do que os primitivos normais podem suportar.

Por exemplo, se seu número inteiro estiver fora do intervalo Long, você provavelmente deve usar o BigInteger. Porém, esses casos são muito raros e o uso dessas classes tem uma sobrecarga significativamente maior do que suas contrapartes primitivas.

Por exemplo, longtem 64 bits de largura e pode conter o intervalo: -9.223.372.036.854.775.808 a 9.223.372.036.854.775,80. ulong pode conter de 0 a 18.446.744.073.709.551.615. Se seus números forem maiores ou menores que isso, o BigInteger é sua única opção

A única vez que os vi usados ​​em um aplicativo do mundo real foi um aplicativo de diagrama de estrelas.

Consulte também: Intervalos primitivos no .NET


Quero dizer, claro, eu sei que devemos usar primitivas normais sempre que pudermos. Quero dizer, como o BigInteger foi projetado para números 100 vezes maiores que o ULong.MaxValue ou o BigInteger foi projetado para números 100k vezes maiores que o ULong.MaxValue? Quer dizer, eu sei que ele pode suportar 100k vezes maior que ULong.MaxValue, mas foi projetado com esse intervalo em mente ou com este intervalo declarado "requisito fora do comum"?
Pacerier 02/08/19

5
Você não pode representar um número nem um maior que ULong.MaxValue sem usar o BigInteger, por isso é para isso. Qualquer número que possa ser maior que ULong.MaxValue deve ser um BigInteger.
Malfist 02/08/19

é claro que existem maneiras de representar números maiores que ULong.MaxValue e sem usar o BigInteger. Eu poderia simplesmente escrever uma estrutura personalizada que consiste em um ULong e um booleano e viola, que eu posso representar até duas vezes do ULong
MaxValue #

Sim, mas é muito menos complicado usar o BigInteger, e provavelmente não seria muito mais rápido, senão mais rápido, e não seria tão flexível quanto o BigInteger. Você também pode representar números muito grandes com uma matriz de booleanos, mas isso é muito complicado.
Malfist 02/08/19

2
@Mavrik, ele mudou isso para uma pergunta completamente diferente daquela que eu respondi.
Malfist 03/08/19

4

Em certo sentido, o objetivo do BigInteger não é tanto o tamanho absoluto, como é uma precisão ilimitada. Os números de ponto flutuante também podem ser muito grandes, mas com precisão limitada. O BigInteger permite executar aritmética sem se preocupar com erros de arredondamento ou estouro. O preço que você paga é que é centenas de vezes mais lento que a aritmética com números inteiros comuns ou números de ponto flutuante.

Como outros já apontaram, o ulong pode manter-se entre 0 a 18.446.744.073.709.551.615, e enquanto você permanecer nesse intervalo, poderá fazer aritmética exata. Se você ultrapassar 1 ponto acima desse intervalo, haverá uma sobrecarga; portanto, a resposta para sua pergunta é usar o BigInteger se você precisar de aritmética exata e se houver possibilidade de que qualquer resultado intermediário exceda 18.446.744.073.705.515.615.

A maioria dos problemas em ciência, engenharia e finanças pode viver com as aproximações forçadas pelos números de ponto flutuante e não pode arcar com o custo de tempo da aritmética do BigInteger. A maioria dos cálculos comerciais não pode viver com as aproximações da aritmética de ponto flutuante, mas funciona no intervalo de 0 a 18.446.744.073.709.551.615, para que eles possam usar a aritmética comum. O BigInteger é necessário ao usar algoritmos da teoria dos números, que incluem coisas como criptografia (pense em números primos de 50 dígitos). Às vezes, também é usado em aplicações comerciais quando são necessários cálculos exatos, a velocidade não é muito importante e a instalação de um sistema de ponto decimal fixo adequado é um problema demais.

Se implementada corretamente, a complexidade da aritmética do BigInteger deve ser uma curva suave. Por exemplo, a complexidade temporal da multiplicação deve ser O (NM), onde N é o número de dígitos no primeiro multiplicando e M é o número de dígitos no segundo multiplicando. É claro que existem limites práticos em que você pode escolher N e M tão grandes que os números não cabem em sua máquina.

Se você pesquisar "Complexidade computacional do biginteger" no Google, obterá mais referências do que pode usar. Um que fala diretamente à sua pergunta é o seguinte: Comparação de dois pacotes aritméticos de precisão arbitrários .


4

Limite de memória

O BigInteger depende da matriz int para armazenamento. Assumindo isso, o limite teórico para o número máximo que o BigInteger é capaz de representar, pode ser derivado do tamanho máximo da matriz disponível em .net. Há um tópico SO sobre matrizes aqui: Descobrindo quanta memória eu posso alocar para uma matriz em C # .

Supondo que sabemos o tamanho máximo da matriz, podemos estimar o número máximo, que o BigInteger pode representar: (2 ^ 32) ^ max_array_size, em que:

  • 2 ^ 32 - número máximo na célula da matriz (int)
  • max_array_size - tamanho máximo permitido da matriz int, limitado pelo tamanho do objeto de 2 GB

Isso fornece um número com 600 milhões de dígitos decimais.

Limite de desempenho

Quanto ao desempenho, o BigInteger usa o algoritmo Karatsuba para multiplicação e o algoritmo linear para adicionar. A complexidade da multiplicação é 3 * n ^ 1,558, o que significa que ela será dimensionada muito bem, mesmo para grandes números ( gráfico de complexidade ), no entanto, você ainda poderá sofrer uma penalidade de desempenho, dependendo do tamanho da RAM e do cache do processador.

Até o momento, como o tamanho máximo do número é limitado a 2 GB, na máquina descendente, você não verá uma lacuna inesperada no desempenho, mas ainda operando com 600 milhões de números de dígitos ficará muito lento.


essa é uma informação maravilhosa; no entanto, onde está sua fonte na qual o BigInteger conta com matrizes int?
Pacerier 03/08/19

Acabei de pesquisar fontes .net usando dotPeek. Parece que o próprio número é armazenado dentro dos dados uint [] _ ​​da estrutura do BigInteger.
Valera Kolupaev 03/08/19

* Atualizado com uma resposta mais detalhada, no entanto, não consigo encontrar nenhum código-fonte .net, ao qual eu possa me referir, exceto trechos descompilados.
Valera Kolupaev 4/08

Parece-me que há um algoritmo de multiplicação Standart em .NET, pois ele pode ser descoberto a partir ILSpy: .NET BigInteger Multiplicação
Ivan Kochurkin

1

O limite é o tamanho da sua memória (e o tempo que você tem). Então, você pode ter números realmente grandes. Como disse Kevin, na criptografia é preciso multiplicar ou exponenciar números com alguns milhares de dígitos (binários), e isso é possível sem problemas.

Obviamente, frequentemente os algoritmos ficam mais lentos à medida que os números aumentam, mas não muito mais lentos.

Quando você estiver usando números no intervalo de mega dígitos, você pode querer pensar em outras soluções - pois o cálculo com elas também fica lento.


0

Existem alguns usos na comunidade científica (ou seja, a distância entre galáxias, número de átomos em um campo de grama, etc.)


para não ser rude ... mas como essa resposta está relacionada à pergunta?
Pacerier 2/08

2
A pergunta, conforme escrita, parece que ele estava procurando um exemplo do mundo real sobre por que esse tipo de dados precisaria ser criado.
Dave Sábio

uma reformulação melhor seria "BigInteger é realmente adequado para números tão grandes quanto 10 ^ 30"?
Pacerier 02/08/19

Para isso, seria melhor usar doubleou float- você não tem a precisão necessária de qualquer maneira.
Pa Elo Ebermann 2/08

uma reformulação melhor seria "o BigInteger é realmente adequado para números tão grandes quanto 10 ^ 30 quando precisamos da precisão"?
Pacerier 02/08/19

0

Como sugere a resposta de kevin cline, os BigNumbers foram adicionados às bibliotecas .NET principalmente porque eram necessários como base para muitos algoritmos criptográficos modernos (assinaturas digitais, criptografia de chave pública / privada etc.). Muitos algoritmos criptográficos modernos envolvem cálculos em valores inteiros com tamanhos de até milhares de bits. Como a classe BigNumber descreve uma classe bem definida e útil, eles decidiram torná-la pública (em vez de mantê-la como um detalhe interno das APIs criptográficas).


btw: apenas curioso, onde está sua fonte de que os BigNumbers foram adicionados às bibliotecas .NET principalmente porque eram necessários como base para muitos algoritmos criptográficos modernos (e, portanto, devem ser capazes de suportar valores de vários milhares de bits)?
Pacerier 03/08/19
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.