Gestire numeri estremamente grandi in una lingua che non può?


15

Sto cercando di pensare a come farei per fare calcoli su numeri estremamente grandi (all'infinito - interger senza float) se il costrutto del linguaggio non è in grado di gestire numeri più grandi di un certo valore.

Sono sicuro di non essere il primo né l'ultimo a porre questa domanda, ma i termini di ricerca che sto usando non mi danno un algoritmo per gestire quelle situazioni. Piuttosto, la maggior parte dei suggerimenti offre un cambio di lingua o variabile o parla di cose che sembrano irrilevanti per la mia ricerca. Quindi ho bisogno di una piccola guida.

Vorrei delineare un algoritmo come questo:

  1. Determina la lunghezza massima della variabile intera per la lingua.

  2. Se un numero è superiore alla metà della lunghezza massima della variabile, suddividerlo in un array. (dai una piccola sala giochi)

  3. Ordine array [0] = i numeri più a destra [n-max] = numeri più a sinistra

    Ex. Num: 29392023 Array [0]: 23, Array [1]: 20, array [2]: 39, array [3]: 29

Da quando ho stabilito la metà della lunghezza della variabile come punto di demarcazione posso quindi calcolare quelli, i decimi, i centesimi, ecc. Posizionare tramite il segno a metà in modo che se una lunghezza massima variabile fosse di 10 cifre da 0 a 9999999999, allora so che dimezzandolo a cinque cifre mi dà un po 'di sala giochi.

Quindi, se aggiungo o moltiplico, posso avere una funzione di controllo variabile che vede che la sesta cifra (da destra) dell'array [0] è la stessa posizione della prima cifra (da destra) dell'array [1].

La divisione e la sottrazione hanno i loro problemi a cui non ho ancora pensato.

Vorrei sapere quali sono le migliori implementazioni per supportare un numero maggiore di quanto il programma possa fare.


1
La prima cosa che mi viene in mente è BigInteger di Java: docs.oracle.com/javase/6/docs/api/java/math/BigInteger.html
Ivan

È una lingua che chiunque qui potrebbe conoscere ed essere in grado di formulare raccomandazioni specifiche o è qualcosa di oscuro e proprietario?
FrustratedWithFormsDesigner

Non so per quale lingua vorrei ancora questo. Conosco PHP di più, ma non voglio farlo in quella lingua. Lisp è attraente poiché da quello che ho letto non ha limiti di lunghezza. Tuttavia, il mio difetto personale nel voler sapere come funziona mi fa venir voglia di avere la libertà di farlo in qbasic se fossi bloccato su un'isola. (È anche per divertimento, penso sempre al calcolo di grandi numeri e alcuni calcolatori online sono troppo ingombranti per il compito.)
Mallow,

Risposte:


25

Stai cercando una libreria aritmetica di precisione arbitraria (chiamata anche "precisione multipla" o "big num") per la lingua con cui stai lavorando. Ad esempio, se lavori con C puoi usare la GNU Bignum Library -> http://gmplib.org/

Se vuoi capire come funziona puoi anche scrivere la tua grande biblioteca numerica e usarla. Il modo più semplice per gestirlo è con gli array, in cui ogni elemento è una cifra del numero con cui stai lavorando. Successivamente è necessario implementare tutte le funzioni per aggiungere, sottrarre, moltiplicare, dividere, esponere e così via.


5
naturalmente "digit" è relativo, molte librerie bignum usano cifre in base 256 (byte senza segno []) a 2 ^ 64 (unsigned long [])
maniaco del cricchetto

1
Solo assicurandomi di aver capito, 'digit' potrebbe essere un array di 256 caratteri di base? Penso che potrei sbagliarmi, fare matematica sulla base 256 è più facile della base 88 ma è ancora piuttosto un compito ... (Almeno quando l'ho fatto ieri sera su un foglio di carta haha)
Mallow,

1
"fare matematica sulla base 256 è più facile della base 88". Falso. Sono ugualmente facili.
S.Lott

2
@ S.Lott: um ... quando hai a disposizione operazioni bit per bit, fare matematica sulla base 256 è decisamente più facile della base 88.
Jason S

1
Costruire il tuo add / sottrarre / moltiplicare è abbastanza semplice. La divisione è difficile, tuttavia, a meno che non venga implementata in binario, dove diventa un esercizio di sottrazione condizionale e spostamento dei bit.
Jason S,

13

È un problema ben noto: l'aritmetica di precisione arbitraria

Quando la lingua che stai utilizzando non risolve questo problema, prova innanzitutto a trovare una libreria di terze parti che lo risolva. Se non lo trovi o sei curioso, prova a implementarlo; l'articolo di Wikipedia ha buoni riferimenti alle implementazioni classiche.


6

Quando si ha a che fare con numeri grandi, probabilmente una delle decisioni di progettazione più fondamentali è come rappresenterò il numero elevato?

Sarà una stringa, un array, un elenco o una classe di archiviazione personalizzata (homegrown).

Dopo aver preso tale decisione, le operazioni matematiche effettive possono essere suddivise in parti più piccole e quindi eseguite con tipi di linguaggio nativi come int o intero.

Ho incluso un esempio di AGGIUNTA molto rudimentale in C # .Net che memorizza il numero grande risultante come stringa. Anche i "numeri" in arrivo sono stringhe, quindi si dovrebbe essere in grado di inviare numeri molto "grandi". Tieni presente che l'esempio è solo per numeri interi per mantenerlo semplice.

Anche con le stringhe c'è un limite nel numero di caratteri o "numeri" nel numero, come indicato qui:

Qual è la lunghezza massima possibile di una stringa .NET?

Ma potresti aggiungere alcuni numeri davvero grandi, ben oltre i tipi nativi int32 o int64 per .Net.

Comunque, ecco un'implementazione di archiviazione delle stringhe.

/// <summary>
/// Adds two "integers".  The integers can be of any size string.
/// </summary>
/// <param name="BigInt1">The first integer</param>
/// <param name="BigInt2">The second integer</param>
/// <returns>A string that is the addition of the two integers passed.</returns>
/// <exception cref="Exception">Can throw an exception when parsing the individual parts     of the number.  Callers should handle. </exception>
public string AddBigInts(string BigInt1, string BigInt2)
{
    string result = string.Empty;

    //Make the strings the same length, pre-pad the shorter one with zeros
    int length = (BigInt1.Length > BigInt2.Length ? BigInt1.Length : BigInt2.Length);
    BigInt1 = BigInt1.PadLeft(length, '0');
    BigInt2 = BigInt2.PadLeft(length, '0');

    int remainder = 0;

    //Now add them up going from right to left
    for (int i = (BigInt1.Length - 1); i >= 0; i--)
    {
        //If we don't encounter a number, this will throw an exception as indicated.
        int int1 = int.Parse(BigInt1[i].ToString());
        int int2 = int.Parse(BigInt2[i].ToString());

        //Add
        int add = int1 + int2 + remainder;

        //Check to see if we need a remainder;
        if (add >= 10)
        {
            remainder = 1;
            add = add % 10;
        }
        else
        {
            remainder = 0;
        }

        //Add this to our "number"
        result = add.ToString() + result;
    }

    //Handle when we have a remainder left over at the end
    if (remainder == 1)
    {
        result = remainder + result;
    }

    return result;
}

Spero che ti dia alcune idee sulla tua implementazione. Si noti che probabilmente il codice di esempio non è ottimizzato o qualcosa del genere. Ha lo scopo di dare alcune idee su come potrebbe essere fatto.


Freddo!! Grazie aiuta a chiarire le cose con i resti che avrei complicato un po 'di più.
Mallow,

-2

Questo funziona più velocemente per me:

static string Add(string a, string b)
        {
            string c = null;

            if (Compare(a, b) < 0)
            {
                c = a;
                a = b;
                b = c;
            }

            StringBuilder sb = new StringBuilder();

            b = b.PadLeft(a.Length, '0');

            int r = 0;

            for (int i = a.Length - 1; i >= 0; i--)
            {
                int part = a[i] + b[i] + r - 96;

                if (part <= 9)
                {
                    sb.Insert(0, part);

                    r = 0;
                }
                else
                {
                    sb.Insert(0, part - 10);

                    r = 1;
                }
            }

            if (r == 1)
            {
                sb.Insert(0, "1");
            }

            return sb.ToString();
        }

2
Questo sito è su questioni concettuali e le risposte sono tenuti a spiegare le cose. Lanciare i dump del codice invece della spiegazione è come copiare il codice dall'IDE alla lavagna: può sembrare familiare e persino a volte comprensibile, ma sembra strano ... solo strano. La lavagna non ha compilatore
moscerino

Questo sito è SCAMBIO, quindi cerchiamo di aiutarci a vicenda il più possibile. Forse dovrei fare tali commenti in StackOverflow, ma ho cercato di aiutare con il mio approccio. Se qualcuno ha ancora bisogno di una spiegazione, la chiederà. Faccio qui un'aggiunta matematica standard cifra per cifra, a partire dalla fine.
Andranik Sargsyan,

D'accordo con moscerino. Almeno spiegare l'algoritmo prima di scaricare il codice.
Frank Hileman,

Basta scaricare il codice senza alcuna spiegazione è come incoraggiare il copia e incolla. Non vedo come ciò possa essere utile in SoftwareEngineering. Forse su StackOverflow è, ma entrambi i siti hanno scopi totalmente diversi.
Laiv,
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.