qualsiasi documento che dice esattamente per quale intervallo di numeri sono progettati .NET BigIntegers?


12

Sto giocando con .NET BigInteger e fondamentalmente mi chiedo quale numero - una risposta stimata andrebbe bene - è il punto di deviazione della curva di (il grafico di (aumento del tempo richiesto per le operazioni) vs (valore di BigInteger))?

o sono progettati senza una tale deviazione tale che se tracciamo l'aumento del tempo richiesto per le operazioni rispetto al valore di BigInteger da 1 a infinito, avremo una curva uniforme fino in fondo?

ad esempio, supponendo che le matrici siano progettate con la capacità di gestire 50 elementi. questo significa che se ho 1 oggetto, le operazioni sono f (1) tempo. e quando ho 2 articoli, le operazioni sono f (2) tempo. se ho 50 articoli, le operazioni sono f (50). ma poiché è progettato per gestire solo 50 articoli, le operazioni eseguite quando avremo 51 articoli saranno g (51) dove g (51)> f (51).

Se implementato correttamente, la complessità dell'aritmetica di BigInteger dovrebbe essere una curva regolare. Ad esempio, la complessità temporale della moltiplicazione dovrebbe essere O (NM) dove N è il numero di cifre nel primo multiplo e M è il numero di cifre nel secondo multiplo. Ovviamente ci sono dei limiti pratici in quanto puoi scegliere N e M così grandi che i numeri non si adatteranno alla tua macchina.

Esistono / sono a conoscenza di documenti che affermano che è stato implementato come tale?


3
Elettori @Down, i voti negativi non significano nulla se non si può lasciare un commento che spiega perché la domanda non è una buona domanda. Ho votato questo perché non vedo alcun problema.
The Muffin Man

Non ho votato in negativo, ma non sono sicuro di quale sia la domanda qui. Vuoi conoscere la complessità di runtime / memoria delle operazioni sui bigints (addizione, moltiplicazione, divisione ecc.)?
nikie,

ad esempio, supponendo che le matrici siano progettate con la capacità di gestire 50 elementi. questo significa che se ho 1 oggetto e le operazioni sono f (1) tempo. e quando ho 2 articoli, le operazioni sono f (2) tempo. se ho 50 articoli le operazioni sono f (50) tempo. ma poiché è progettato per gestire solo 50 articoli, le operazioni eseguite quando avremo 51 articoli saranno g (51) dove g (51)> f (51)
Pacerier

@Charles E. Grant sì! questo è quello di cui sto parlando. domanda c'è: c'è qualcuno / qualcuno conosce documenti che affermano che è stato implementato come tale?
Pacerier

@Paceier Ho spostato il mio commento nella mia risposta e ho aggiunto un collegamento a un documento che parlava esattamente di questo.
Charles E. Grant,

Risposte:


7

Qualsiasi numero che potrebbe eventualmente diventare maggiore di ULong.MaxValue o inferiore a Long.MinValue dovrebbe essere rappresentato usando BigInteger.

If NOT (Long.MinValue <= X <= ULong.MaxValue) Quindi BigInteger

BigInteger è per numeri troppo grandi di quelli che le primitive normali possono gestire.

Ad esempio, se il tuo numero intero è al di fuori dell'intervallo Long, probabilmente dovresti usare BigInteger. Questi casi sono tuttavia molto rari e l'utilizzo di queste classi ha un sovraccarico significativamente più elevato rispetto alle loro controparti primitive.

Ad esempio, longè largo 64 bit e può contenere l'intervallo: da -9.223.372.036.854.775.808 a 9.223.372.036.854.775,80. ulong può contenere da 0 a 18.446.744.073.709.551.615. Se i tuoi numeri sono più grandi o più piccoli, BigInteger è la tua unica opzione

L'unica volta che li ho visti usati in un'applicazione del mondo reale è stata un'applicazione starchartting.

Vedi anche: intervalli primitivi in ​​.NET


voglio dire, ovviamente, so che dovremmo usare le primitive normali ogni volta che possiamo ... intendo dire che BigInteger è progettato per numeri 100 volte più grandi di ULong.MaxValue o BigInteger è progettato per numeri 100k volte più grandi di ULong.MaxValue? Voglio dire, so che può supportare 100k volte più grande di ULong.MaxValue ma è progettato pensando a questa gamma o è stato progettato con questa gamma dichiarata "requisito fuori dal comune"?
Pacerier

5
Non puoi rappresentare un numero nemmeno uno maggiore di ULong.MaxValue senza usare BigInteger, quindi è per quello. Qualsiasi numero che potrebbe diventare più grande di ULong.MaxValue dovrebbe essere un BigInteger.
Malfist,

ovviamente ci sono modi per rappresentare numeri maggiori di ULong.MaxValue e senza usare BigInteger. potrei semplicemente scrivere una struttura personalizzata che consiste in un ULong, un booleano e una viola che posso rappresentare fino a due volte di ULong.MaxValue
Pacerier

Sì, ma è molto meno complicato utilizzare BigInteger e probabilmente non sarebbe molto più veloce, se non più veloce, e non sarebbe flessibile come BigInteger. Potresti anche rappresentare numeri molto grandi con un array di booleani, ma è troppo complicato.
Malfist,

2
@Mavrik, ha cambiato questa in una domanda completamente diversa da quella a cui ho risposto.
Malfist,

4

In un certo senso il punto di BigInteger non è tanto la dimensione assoluta quanto la precisione illimitata. Anche i numeri in virgola mobile possono essere molto grandi, ma hanno una precisione limitata. BigInteger ti consente di eseguire l'aritmetica senza preoccuparti di errori di arrotondamento o overflow. Il prezzo da pagare è che è centinaia di volte più lento dell'aritmetica con interi ordinari o numeri in virgola mobile.

Come altri hanno sottolineato, ulong può contenere da 0 a 18.446.744.073.709.551.615 e finché rimani in tale intervallo puoi fare un'aritmetica esatta. Se vai anche oltre 1, otterrai un overflow, quindi la risposta alla tua domanda è utilizzare BigInteger se hai bisogno di un'aritmetica esatta e c'è la possibilità che qualsiasi risultato intermedio superi 18.446.744.073.709.551.615.

La maggior parte dei problemi scientifici, ingegneristici e finanziari può convivere con le approssimazioni forzate da numeri in virgola mobile e non può permettersi il costo temporale dell'aritmetica di BigInteger. La maggior parte dei calcoli commerciali non possono convivere con le approssimazioni dell'aritmetica in virgola mobile, ma funzionano nell'intervallo da 0 a 18.446.744.073.709.551.615, quindi possono usare l'aritmetica ordinaria. BigInteger è necessario quando si usano algoritmi dalla teoria dei numeri che include cose come la crittografia (si pensi a numeri primi di 50 cifre). A volte viene anche utilizzato in applicazioni commerciali quando sono necessari calcoli esatti, la velocità non è troppo importante e la creazione di un adeguato sistema di punti decimali fissi è troppo problematica.

Se implementato correttamente, la complessità dell'aritmetica di BigInteger dovrebbe essere una curva regolare. Ad esempio, la complessità temporale della moltiplicazione dovrebbe essere O (NM) dove N è il numero di cifre nel primo multiplo e M è il numero di cifre nel secondo multiplo. Ovviamente ci sono dei limiti pratici in quanto puoi scegliere N e M così grandi che i numeri non si adatteranno alla tua macchina.

Se google "Complessità computazionale di biginteger" otterrai più riferimenti di quanti ne puoi scuotere. Uno che parla direttamente alla tua domanda è questo: confronto tra due pacchetti aritmetici di precisione arbitraria .


4

Limite di memoria

BigInteger si basa sull'array int per l'archiviazione. Supponendo questo, il limite teorico per il numero massimo, che BigInteger è in grado di rappresentare, può essere derivato dalla dimensione massima dell'array disponibile in .net. C'è un argomento SO sugli array qui: Trovare quanta memoria posso allocare per un array in C # .

Supponendo che conosciamo la dimensione massima dell'array, possiamo stimare il numero massimo, che BigInteger può rappresentare: (2 ^ 32) ^ max_array_size, dove:

  • 2 ^ 32 - numero massimo nella cella dell'array (int)
  • max_array_size - dimensione massima consentita dell'array int che è limitata dalla dimensione dell'oggetto di 2 GB

Questo dà il numero con 600 milioni di cifre decimali.

Limite di prestazione

Per quanto riguarda le prestazioni, BigInteger utilizza l' algoritmo Karatsuba per la moltiplicazione e l'algoritmo lineare per l'aggiunta. La complessità della moltiplicazione è 3 * n ^ 1.585, ciò significa che si ridimensionerà abbastanza bene anche per grandi numeri ( grafico di complessità ), tuttavia è ancora possibile colpire la penalità delle prestazioni a seconda delle dimensioni della RAM e della cache del processore.

Per quanto la dimensione massima del numero sia limitata a 2 GB, sulla macchina di discesa non si noterà un gap prestazionale inaspettato, ma continuando a funzionare su numeri di 600 milioni di cifre sarà molto lento.


queste sono informazioni meravigliose, ma dov'è la tua fonte su cui BigInteger si basa su array int?
Pacerier,

Ho appena scavato nei sorgenti .net usando dotPeek. Sembra che il numero stesso sia memorizzato all'interno di uint [] _data della struttura di BigInteger.
Valera Kolupaev,

* Aggiornato con una risposta più dettagliata, tuttavia, non riesco a trovare alcun codice sorgente .net, a cui posso fare riferimento, ad eccezione dei frammenti decompilati.
Valera Kolupaev,

Mi sembra che ci sia un algoritmo di moltiplicazione standart in .NET in quanto può essere capito da ILSpy: NET BigInteger Moltiplicazione
Ivan Kochurkin

1

Il limite è la dimensione della memoria (e il tempo che hai). Quindi, puoi avere numeri davvero grandi. Come affermato da Kevin, nella crittografia si devono moltiplicare o esponere i numeri con alcune migliaia di cifre (binarie), e questo è possibile senza problemi.

Naturalmente, spesso gli algoritmi diventano più lenti man mano che i numeri aumentano, ma non molto più lentamente.

Quando stai usando numeri nell'intervallo di mega cifre, potresti voler pensare ad altre soluzioni, poiché anche il calcolo reale con loro diventa lento.


0

Ci sono alcuni usi all'interno della comunità scientifica (cioè la distanza tra le galassie, il numero di atomi in un campo di erba, ecc.)


non essere scortese ... ma come si collega questa risposta alla domanda?
Pacerier,

2
La domanda, come scritta, sembra che stesse cercando un esempio del mondo reale sul perché tale tipo di dati avrebbe dovuto essere creato.
Dave Wise,

una riformulazione migliore sarebbe "BigInteger è davvero adatto per numeri grandi come 10 ^ 30"?
Pacerier,

Per questo vorrei usare meglio doubleo float- non hai comunque la precisione necessaria.
Paŭlo Ebermann,

una riformulazione migliore sarebbe "BigInteger è davvero adatto per numeri grandi come 10 ^ 30 quando abbiamo bisogno della precisione"?
Pacerier,

0

Come suggerisce la risposta di kevin cline, i BigNumber sono stati aggiunti alle librerie .NET principalmente perché erano necessari come elementi costitutivi di molti moderni algoritmi crittografici (firme digitali, crittografia di chiavi pubbliche / private, ecc.). Molti algoritmi crittografici moderni prevedono calcoli su valori interi con dimensioni fino a diverse migliaia di bit. Poiché la classe BigNumber descrive una classe ben definita e utile, hanno deciso di renderla pubblica (anziché tenerla come un dettaglio interno delle API crittografiche).


tra l'altro, curioso di sapere da dove proviene il fatto che i BigNumber sono stati aggiunti alle librerie .NET principalmente perché erano necessari come elementi costitutivi di molti moderni algoritmi crittografici (e quindi dovrebbero essere in grado di supportare valori fino a diverse migliaia di bit)?
Pacerier,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.