web-dev-qa-db-fra.com

travailler avec des nombres incroyablement grands dans .NET

J'essaie de résoudre les problèmes sur projecteuler.net mais je continue à rencontrer quelques problèmes.

La première consiste à stocker de grandes quantités d’éléments dans un List<t>. Je continue à recevoir OutOfMemoryException lorsque je stocke de grandes quantités dans la liste.

Maintenant, j’admets que je ne ferais peut-être pas ces choses de la meilleure façon, mais existe-t-il un moyen de définir la quantité de mémoire que l’application peut consommer?

Il se bloque généralement quand on a environ 100 000 000 d'éléments: S

Deuxièmement, certaines des questions nécessitent l'ajout de nombres massifs. J'utilise le type de données ulong où le nombre va grossir, mais je parviens à dépasser le plus grand int pris en charge et à obtenir des nombres négatifs.

Avez-vous des conseils pour travailler avec des nombres incroyablement grands?

24
Greg B
23
Larsenal

Vous devez utiliser une classe de grand nombre qui utilise des principes mathématiques de base pour fractionner ces opérations. Cette implémentation d’une bibliothèque C # BigInteger sur CodePoject semble être la plus prometteuse. L'article contient également de bonnes explications sur le fonctionnement des opérations avec des nombres massifs.

Voir aussi: Big integers in C #

27
ine

En ce qui concerne Project Euler, vous risquez d’aborder le mauvais arbre si vous frappez des exceptions OutOfMemory. De leur site web:

Chaque problème a été conçu selon une "règle d'une minute", ce qui signifie que bien qu'il puisse prendre plusieurs heures pour concevoir un algorithme réussi comportant des problèmes plus difficiles, une implémentation efficace permet d'obtenir une solution sur un ordinateur à la puissance modérée. moins d'une minute.

11
Jake Pearson

Comme l’a dit l’utilisateur Jakers, si vous utilisez de grands nombres, vous vous trompez probablement.

Parmi les problèmes que j'ai rencontrés avec ProjectEuler, aucun n’avait encore eu besoin de calculer les grands nombres. Il s’agit plutôt de trouver le bon algorithme pour éviter les grands nombres.

Vous voulez des astuces? Postez ici, et nous pourrions avoir un thread intéressant sur Euler commencé.

4
abelenky

Je suppose que c'est C #? F # a intégré des méthodes pour gérer ces deux problèmes (type BigInt et séquences paresseuses).

Vous pouvez utiliser les deux techniques F # de C #, si vous le souhaitez. Le type BigInt est raisonnablement utilisable à partir d'autres langues si vous ajoutez une référence à l'assembly F # principal.

Les séquences paresseuses sont essentiellement des énumérateurs respectant la syntaxe. Inscrire 100 000 000 d'éléments dans une liste n'est pas un bon plan. Vous devez donc repenser vos solutions pour y remédier. Si vous n'avez pas besoin de conserver des informations, jetez-les! Si c'est moins cher de le recalculer que de le stocker, jetez-le! 

3
MrKurt

Voir les réponses dans ce thread . Vous devrez probablement utiliser l’une des bibliothèques/classes de grand entier tierces disponibles ou attendre C # 4.0, qui inclura un type de données BigInteger natif.

1
Scott Dorman

Vous n'avez pas besoin d'utiliser BigInteger Vous pouvez faire cet événement avec un tableau de chaînes de nombres.

class Solution
{

    static void Main(String[] args)
    {
        int n = 5;
        string[] unsorted = new string[6] { "3141592653589793238","1", "3", "5737362592653589793238", "3", "5" };

        string[] result = SortStrings(n, unsorted);

        foreach (string s in result)
            Console.WriteLine(s);
        Console.ReadLine();
    }
    static string[] SortStrings(int size, string[] arr)
    {

        Array.Sort(arr, (left, right) =>
        {

            if (left.Length != right.Length)
                return left.Length - right.Length;
            return left.CompareTo(right);
        });

        return arr;
    }
}
1
Abhilash Virat

En ce qui concerne la quantité de mémoire qu'une application utilisera, vous pouvez vérifier la mémoire disponible avant d'effectuer une opération à l'aide de MemoryFailPoint class.

Cela vous permet de préallouer de la mémoire avant d'exécuter l'opération. Vous pouvez ainsi vérifier si une opération échouera avant de l'exécuter.

1
Cameron MacFarland

Je ne suis pas sûr que ce soit un bon moyen de le gérer, mais j'utilise les éléments suivants dans mon projet.

J'ai une variable "double theRelevantNumber" et un "int PowerOfTen" pour chaque élément et dans ma classe pertinente, j'ai une variable "int pertinentDecimals". 

Donc ... quand de grands nombres sont rencontrés, ils sont traités comme suit: 

Ils sont d'abord modifiés en forme x, yyy. Donc, si le nombre 123456,789 était entré et que le "powerOfTen" valait 10, cela commencerait ainsi: 

theRelevantNumber = 123456,789 PowerOfTen = 10 Le numéro était alors: 123456,789 * 10 ^ 10

Il est ensuite remplacé par: 1,23456789 * 10 ^ 15

Il est ensuite arrondi par le nombre de décimales pertinentes (par exemple 5) à 1,23456, puis enregistré avec "PowerOfTen = 15".

Lors de l'ajout ou de la soustraction de nombres, tout nombre situé en dehors des décimales pertinentes est ignoré. Signification si vous prenez: 

1 * 10 ^ 15 + 1 * 10 ^ 10 il passera à 1,00001 si "données pertinentes" est 5, mais ne changera pas du tout si "données pertinentes" vaut 4.

Cette méthode vous permet de traiter des nombres jusqu'à doubleLimit * 10 ^ intLimit sans aucun problème, et au moins pour OOP, il n'est pas si difficile de garder trace de cela. 

0
Allan Karseth
string Add(string s1, string s2)
{
        bool carry = false;
        string result = string.Empty;

        if (s1.Length < s2.Length)
            s1 = s1.PadLeft(s2.Length, '0');
        if(s2.Length < s1.Length)
            s2 = s2.PadLeft(s1.Length, '0');

        for(int i = s1.Length-1; i >= 0; i--)
        {
            var augend = Convert.ToInt64(s1.Substring(i,1));
            var addend = Convert.ToInt64(s2.Substring(i,1));
            var sum = augend + addend;
            sum += (carry ? 1 : 0);
            carry = false;
            if(sum > 9)
            {
                carry = true;
                sum -= 10;
            }
            result = sum.ToString() + result;
        }
        if(carry)
        {
            result = "1" + result;
        }

    return result;
}
0
Milod Orif