82 votes

Comment implémenter big int en C ++

J'aimerais mettre en œuvre un grand de la classe int en C++ comme un exercice de programmation. Une classe qui peut traiter des nombres plus grands, alors un long int. Je sais qu'il existe plusieurs implémentations open source là déjà, mais je voudrais écrire ma propre. Ce que j'essaie d'avoir une idée de ce que la bonne approche est.

Je comprends que la stratégie générale est d'obtenir le numéro de chaîne, puis le diviser en plus petits nombres (chiffres simples par exemple), et les placer dans un tableau. À ce stade, il devrait être relativement simple à mettre en œuvre les différents opérateurs de comparaison. Ma principale préoccupation est la façon dont je voudrais mettre en œuvre des choses comme l'addition et la multiplication.

Je suis à la recherche d'une approche générale et les conseils de l'apposer au code de travail effectif.

46voto

mstrobl Points 1571

Un défi amusant. :)

Je suppose que vous voulez des entiers de taille arbitraire. Je vous propose la démarche suivante:

Considérer la nature binaire du type "int". Penser à l'aide de simples opérations binaires pour imiter ce que les circuits de votre CPU n'lorsqu'ils ajoutent des choses. Dans le cas où vous êtes intéressé plus en profondeur, il est conseillé de lire cet article de wikipédia sur la demi-additionneurs et plein additionneurs. Vous allez faire quelque chose de semblable à cela, mais vous pouvez descendre aussi bas niveau que celle - mais paresseuse, je pensais que je voudrais simplement renoncer à et de trouver une solution plus simple.

Mais avant d'aller dans n'importe quel algorithmique des détails sur l'ajout, soustraction, la multiplication, nous allons trouver des données de la structure. Une manière simple, est bien sûr, pour stocker des choses dans un std::vector.

template< class BaseType >
class BigInt
{
typedef typename BaseType BT;
protected: std::vector< BaseType > value_;
};

Vous pourriez envisager si vous souhaitez faire le vecteur d'une taille fixe et si de préallouer. La raison en est que pour diverses opérations, vous aurez à passer par chaque élément du vecteur - O(n). Vous voulez savoir comment désinvolte complexe d'une opération est un fixe n est juste que.

Mais maintenant, pour certains algorithmes d'exploitation sur les nombres. Vous pourriez le faire sur une logique de niveau, mais nous allons utiliser cette magie, la puissance du PROCESSEUR pour calculer les résultats. Mais ce que nous allons prendre la relève de la logique-illustration de la Moitié - et FullAdders est la façon dont il traite avec porte. Par exemple, considérez comment vous pouvez mettre en œuvre l' opérateur+= . Pour chaque numéro de type BigInt<>::value_, vous devez ajouter à ceux-ci et voir si le résultat produit une certaine forme de portage. Nous n'allons pas faire de bit-wise, mais dépendent de la nature de notre BaseType (que ce soit long ou int ou de courte ou de quoi que ce soit): il déborde.

Sûrement, si vous ajoutez les deux chiffres, le résultat doit être supérieure à la plus un de ces numéros, à droite? Si elle ne l'est pas, alors le résultat débordé.

template< class BaseType >
BigInt< BaseType >& BigInt< BaseType >::operator += (BigInt< BaseType > const& operand)
{
  BT count, carry = 0;
  for (count = 0; count < std::max(value_.size(), operand.value_.size(); count++)
  {
    BT op0 = count < value_.size() ? value_.at(count) : 0, 
       op1 = count < operand.value_.size() ? operand.value_.at(count) : 0;
    BT digits_result = op0 + op1 + carry;
    if (digits_result-carry < std::max(op0, op1)
    {
      BT carry_old = carry;
      carry = digits_result;
      digits_result = (op0 + op1 + carry) >> sizeof(BT)*8; // NOTE [1]
    }
    else carry = 0;
  }

  return *this;
}
// NOTE 1: I did not test this code. And I am not sure if this will work; if it does
//         not, then you must restrict BaseType to be the second biggest type 
//         available, i.e. a 32-bit int when you have a 64-bit long. Then use
//         a temporary or a cast to the mightier type and retrieve the upper bits. 
//         Or you do it bitwise. ;-)

L'autre opération arithmétique aller analogue. Heck, vous pouvez même utiliser la stl-foncteurs std::plus et std::moins, std::temps et std::divise, ..., mais l'esprit de la transporter. :) Vous pouvez aussi mettre en œuvre la multiplication et la division à l'aide de votre plus et moins opérateurs, mais c'est très lent, parce que ce serait recalculer les résultats que vous avez déjà calculé en avant les appels à plus et moins à chaque itération. Il y a beaucoup de bons algorithmes pour cette tâche simple, utiliser wikipédia ou sur le web.

Et bien sûr, vous devez mettre en œuvre la norme des opérateurs tels que operator<< (passez chaque valeur de value_ à gauche de n bits, en commençant à l' value_.size()-1... oh et n'oubliez pas le porter :), operator< - vous pouvez même optimiser un peu ici, la vérification de la rugueuse nombre de chiffres avec size() première. Et ainsi de suite. Faites ensuite votre classe utile, par befriendig std::ostream operator<<.

Espérons que cette approche est utile!

38voto

Harper Shelby Points 13395

Les choses à considérer pour une grande classe int:

  1. Opérateurs mathématiques: +, -, /, *, % N'oubliez pas que votre classe peut-être de chaque côté de la l'opérateur, que les opérateurs peuvent être enchaînés, que l'un des opérandes pourrait être un int, float, double, etc.

  2. I/O opérateurs: >>, << C'est où que vous comprendre comment correctement créer votre classe à partir de la saisie de l'utilisateur, et comment mettre en forme pour la sortie.

  3. Conversions/Jette: comprendre quels sont les types/classes de votre grand int la classe doit être convertibles et comment faire pour gérer correctement l' la conversion. Une rapide liste serait inclure double et float, et peut inclure int (avec des limites acceptables la vérification) et complexe (en supposant qu'il peut gérer la gamme).

30voto

orcmid Points 1700

Il y a une section complète sur ce point: [L'Art de la Programmation Informatique, vol.2: Seminumerical Algorithmes, la section 4.3 de Multiples Précision Arithmétique, pp. 265-318 (ed.3)]. Vous pouvez trouver d'autres matériels intéressants dans le Chapitre 4, l'Arithmétique.

Si vous ne voulez vraiment pas à regarder une autre mise en œuvre, avez-vous songé à ce que vous êtes à la recherche d'informations? Il existe d'innombrables erreurs à faire et à découvrir de ceux qui est instructif et aussi dangereux. Il y a aussi des défis à relever dans l'identification important de calcul des économies et d'avoir de stockage approprié des structures pour éviter de graves problèmes de performances.

Une Question pour vous: Comment avez-vous l'intention de tester votre application et comment vous proposez-vous pour démontrer que c'est de l'arithmétique est-elle correcte?

Vous pourriez vous en voulez une autre mise en œuvre à tester (sans regarder la façon dont elle le fait), mais il faudra plus que cela pour être en mesure de généraliser sans attendre une excrutiating niveau de test. N'oubliez pas de tenir compte des modes de défaillance (en dehors des problèmes de mémoire, hors de la pile, la course trop long, etc.).

Amusez-vous!

7voto

adi92 Points 4589

addition devrait probablement être fait dans l'algorithme de temps linéaire standard
mais pour la multiplication, vous pouvez essayer http://en.wikipedia.org/wiki/Karatsuba_algorithm

5voto

utku_karatas Points 3513

Fait intéressant, je venais de regarder une vidéo à ce sujet avant de voir votre question. Voici le lien . Courtesy of Chaos Communication Congress.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X