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

15

Sto cercando di pensare a come fare i calcoli su numeri estremamente grandi (all'infinito - non interpone alcuno 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 utilizzando non mi forniscono un algoritmo per gestire tali situazioni. Piuttosto, la maggior parte dei suggerimenti offre un cambio di lingua o un cambiamento variabile o parla di cose che sembrano irrilevanti alla mia ricerca. Quindi ho bisogno di un po 'di guida.

Vorrei abbozzare un algoritmo come questo:

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

  2. Se un numero è più della metà della lunghezza della lunghezza massima della variabile, suddividila in una matrice. (dai una piccola sala giochi)

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

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

Dato che ho stabilito metà della lunghezza della variabile come punto di riferimento, posso calcolare i decimi, i centesimi, ecc. Posizionare tramite il segno a metà, in modo che se la lunghezza massima variabile fosse 10 cifre da 0 a 9999999999, allora So che con l'halfing a cinque cifre mi danno una stanza da gioco.

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 della prima cifra (da destra) dell'array [1] .

Dividere e sottrarre hanno i loro problemi che non ho ancora pensato.

Mi piacerebbe conoscere le migliori implementazioni di supportare numeri più grandi di quanto possa fare il programma.

    
posta Mallow 20.01.2012 - 21:46
fonte

4 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 stai lavorando con C puoi usare GNU Bignum Library - > link

Se vuoi capire come funziona puoi anche scrivere la tua libreria num num e usarla. Il modo più semplice per gestirlo è con gli array, in cui ogni elemento è una cifra del numero con cui si sta lavorando. Dopodiché è necessario implementare tutte le funzioni per aggiungere, sottrarre, moltiplicare, dividere, esponenziare e così via.

    
risposta data 20.01.2012 - 21:53
fonte
13

È un problema ben noto: Aritmetica arbitraria di precisione

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

    
risposta data 20.01.2012 - 22:00
fonte
6

Quando si ha a che fare con numeri grandi, probabilmente una delle decisioni progettuali fondamentali è come rappresenterò il grande numero?

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

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

Ho incluso un esempio di ADDITION molto rudimentale in C # .Net che memorizza il grande numero risultante come una stringa. Anche i "numeri" in entrata sono stringhe, quindi si dovrebbe poter 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 a. Stringa NET?

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

Ad ogni modo, ecco un'implementazione per la memorizzazione di 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 il codice di esempio probabilmente non è ottimizzato o qualcosa del genere. Ha lo scopo di dare alcune idee su come potrebbe essere fatto.

    
risposta data 20.01.2012 - 23:07
fonte
-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();
        }
    
risposta data 30.04.2017 - 07:47
fonte

Leggi altre domande sui tag