Comment imprimer de très gros nombres en C++
j'ai ce code
#include <iostream>
using namespace std;
int main(int argc,char **argv) {
unsigned long long num1 = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999995LL;
unsigned long long num2 = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999996LL;
unsigned long long num3 = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999997LL;
unsigned long long num4 = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998LL;
unsigned long long num5 = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999LL;
cout << (unsigned long long)(num1 * num2 * num3 * num4 * num5) << endl;
return 0;
}
comme vous pouvez le voir les nombres sont énormes, mais quand je fais le calcul là-bas je reçois ce: 18446744073709551496
au moment de la compilation je reçois ces avertissements:
warning: integer constant is too large for its type|
In function `int main(int, char**)':|
warning: this decimal constant is unsigned only in ISO C90|
...
7 réponses
votre résultat est plus grand que le type long long - vous devez regarder un BigInteger ou bibliothèque de précision arbitraire, quelque chose comme gmp
ces nombres ne correspondent à aucun type de données C++. Si vous voulez juste les imprimer, stockez les numéros dans une chaîne. Si vous voulez faire des maths sur elle, trouver une précision arbitraire bibliothèque de mathématiques et l'utiliser.
si vous voulez des caractères aussi gros dans votre code, vous devrez les entrer comme des caractères littéraux à cordes et les charger dans une sorte de classe de BigInt. Il n'y a aucun moyen d'exprimer des entiers littéraux aussi grands dans le code source en ce moment (bien que C++0x va, espérons-le, combler cette lacune).
si vous utilisez la bibliothèque BigInteger , jetez un oeil à la fonction stringToBigUnsigned
dans BigIntegerUtils.hh
pour construire un grand entier à partir d'une chaîne.
#include "BigUnsigned.hh"
#include "BigIntegerUtils.hh"
BigUnsigned num1 = stringToBigUnsigned (
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999999999999999999999999999999999999999999999999"
"99999999999999999999999999999999999995"
);
qu'est-Ce que vous essayez de faire? Comprenez-vous les bases des nombres binaires et décimaux? Pourquoi 8 bits ne contient que les valeurs 0 à 255, 12 bits 0-4095, etc.? Combien de bits faut-il pour maintenir le numéro qui vous intéresse? Ou mieux, Quelle est la taille d'un nombre que vous êtes intéressé à créer? Et tu utilises des 9 pour augmenter le nombre? Qu'en est hex 0xF... au lieu de cela? Si vous voulez le plus grand nombre non signé (dans l'un des types integer standard) pourquoi pas:
non signé long long A, b;
a = -1; //ce qui semble tout simplement mauvais mélange signés et non signés, mais il est valide, le nombre est converti en unsigned avant de le ranger
b = 0; b--; //fait la même chose que ci-dessus
avez-vous vraiment besoin de précision à ce niveau? Vous réalisez que les multiplies peuvent exiger un résultat deux fois la taille de chaque opérande? 0xFF * 0xFF = 0xFE01, si dans ce cas vous utilisiez des entiers de 8 bits, vous pourriez ne fais pas le calcul. Cela ne fait qu'empirer alors que vous continuez à multiplier 0xFF * 0xFF * 0xFF = 0xFD02FF.
Ce que tentent de faire?
voir votre réponse:
Je n'ai jamais vu euler numéro 8 avant. Cela ressemble à une bonne question d'interview car il suffit de quelques lignes de code pour résoudre.
votre autre réponse:
Numéros...
probablement parce que nous avons 10 doigts (et peut-être 10 orteils) nous grandissons avec "base 10". Nos horloges sont la base 60 pour la plupart, mais elle a été mélangée à la base 10 pour la rendre plus confuse. Quoi qu'il en soit, base 10, signifie que pour chaque numéro placeholder vous avez un des 10 chiffres uniques, lorsque vous atteignez le maximum dans cet endroit vous roulez à l'endroit suivant. C'est tout de l'école élémentaire des choses.
000
001
002
003
...
008
009
010
011
012
...
voir comment le chiffre le plus à droite a 10 symboles (0,1,2,3,4,5,6,7,8,9) et quand il atteint le dernier symbole il commence plus et celui à gauche de lui augmente d'un. Cette règle est vraie pour tous systèmes de numérotation de base.
c'est vrai pour la base 2 sauf qu'il n'y a que deux symboles, 0 et 1
000
001
010
011
100
101
...
est de Même pour l'octal, mais 8 symboles (0,1,2,3,4,5,6,7)
000
Zero zero un
002
003
004
005
006
007
010
011
012
013
...
et il en est de même pour l'hexadécimal, 16 symboles (0,1,2,3,4,5,6,7,8,9,a,b,c,D,e,f)
000
001
002
003
004
005
006
007
008
009
00a
00b
C 00
00d
00e
00f
010
011
012
013
...
j'étais sur le point d'entrer dans le pourquoi de l'utilisation binaires sur d'autres bases (10) dans les ordinateurs. Au bout du compte, il est facile d'avoir deux états allumés ou éteints, ou hauts et bas. Deux états est comme deux symboles 1 et 0 en base 2. Essayer de garder l'électronique à l'écoute de plus de deux états dans la tension disponible est difficile, au moins il autrefois, il était relativement facile de le maintenir près de zéro volts ou au-dessus d'un petit nombre de volts, de sorte que l'Électronique Numérique utilise deux états binaires.
même une tâche simple pour un humain en binaire est longtemps enroulé, mathématiques simples de deuxième année est encore beaucoup de uns et de zéros. Donc, octal est devenu populaire parce qu'il vous a permis de réfléchir en groupes de trois bits et vous pouvez utiliser les symboles qui nous sont familiers avec comme les numéros de 0,1,2,3,4,5,6,7. Mais les groupes de quatre qui est une autre puissance de 2, donne aux humains beaucoup plus de puissance de calcul mental que octal, hex est basé sur 4 bits qui est aussi une puissance de 2. Nous avons dû ajouter plus de symboles aux 10 que nous avons empruntés à la base arabe traditionnelle 10, donc le premier 6 de l'alphabet a été utilisé. Octal est rarement si jamais utilisé, vous pouvez dire à quelqu'un l'âge s'ils pensent octal au lieu de hexagones. (Je suis de la génération hex mais j'ai travaillé avec ceux de la génération octal qui luttent avec hex parce qu'ils ne peuvent pas passer de l'octal au binaire à hex en leur esprit).
la Base 10 dans un ordinateur est comme la pensée humaine moyenne dans hex. les ordinateurs ne font pas la base 10 (bien pour les humains paresseux ils ont utilisé pour faire bcd), ils font la base 2. Le nombre décimal 1234 dans un ordinateur est vraiment 0x4D2 ou 0b010011010010. C'est comme une valeur, disons que vous voulez ajouter 1234 plus un autre nombre dont vous avez besoin cette valeur qui n'a rien à voir avec les symbos 1, 2, 3, et 4. Mais pour poster cette réponse sur stackoverflow nous n'utilisons pas le nombre que nous utilisons ASCII, donc 1234 en ascii est 0x31, 0x32, 0x33, 0x34, ce qui est important de savoir pour votre solution d'euler supposant le nombre de 1000 chiffres a été fourni comme une chaîne ascii, qu'il devrait être ou vous auriez à le convertir De binaire en ascii puisque le problème est un problème de base 10 et non de base 2 par définition.
donc revenons à ce que j'avais demandé. Si vous aviez 4 bits de mémoire pour stocker un numéro, quelle taille de numéro pourriez-vous stocker? Si vous pensez que la base 10 seulement vous pourriez penser que ce nombre est a 9, parce que vous êtes formé à penser à l'utilisation du plus grand symbole dans chaque lieu de stockage, 99999 est le plus grand nombre si vous avez 5 lieux de stockage dans la base 10. Retour à quatre bits cependant, le plus grand symbole pour un seul bit est 1, Mettez ce nombre dans chaque emplacement de stockage que vous obtenez 1111 (quatre uns). Juste en regardant ces quatre, vous devriez être en mesure de dans votre esprit facilement voir la version octal et hexagone de ce même nombre 17 octal ou hexagone. Pour voir décimal prend des maths, ou dans ce cas la mémorisation, ce nombre est de 15 décimales. Donc le plus grand nombre de quatre bits que vous pouvez avoir est 0xF ou 15 Pas 9. Qu'en 8 bits? 0xFF ou 255 (2 à la 8ème puissance moins un). Le plus grand nombre de 16 bits? 65535, etc.
donc quand je demande combien de bits essayez-vous d'utiliser, c'est ce que je veux dire. Regardez ce numéro 99999. Encore une fois base 10 vous penseriez que c'est le plus grand nombre, mais pour un ordinateur il est seulement à mi-chemin là, 99999 décimal est 0x1869F, qui prend 17 bits de mémoire à stocker, le plus grand nombre de 17 bits que vous pouvez stocker est 0x1ff qui est 131071 qui est un peu plus grand que 99999. Donc, quand vous voulez penser de grands nombres et des mathématiques sur un ordinateur, vous devez penser binaire (ou hex).
à l'Origine vous faisiez des multiplications, ce qui fait toujours partie du problème d'euler, mais ce que je demandais était lié à la précision et au stockage de bits. Voici quelques principes fondamentaux, et je ne vais pas entrer dans cela, mais vous pouvez voir pourquoi nous comptons sur flottant unités de pointage dans les ordinateurs.
prendre le plus grand nombre de 4 bits 1111(binaire), qui est de 15 décimales. Ajoutez cela avec le plus grand nombre de quatre bits et vous obtenez 15+15 = 30 = 0x1E ou 11110 binaire. Donc pour ajouter deux nombres de quatre bits vous avez besoin de cinq bits pour tenir votre réponse. Les ordinateurs conservent un" carry " bit pour ce bit supplémentaire. Essentiellement, les fonctions mathématiques ajouter / soustraire des entiers dans l'ordinateur vous permettent d'avoir N+1 bits. Donc si c'est un ordinateur 32 bits vous avez essentiellement 33 bits pour add / sub mathématique.
le problème est de multiplier et diviser, ce que même aujourd'hui beaucoup de processeurs ne supportent pas (oui beaucoup n'ont pas de fpu et ne font qu'ajouter et soustraire, parfois multiplier, mais diviser est rare. Multiplier et diviser prendre beaucoup d'électronique le compromis est que vous pouvez les faire avec des additions et soustractions dans le logiciel). Prendre le pire des cas multiplier pour un système de quatre bits 1111 * 1111 = 11100001 donc il faut 8 bits pour stocker le résultat d'un 4 bits multiplier, vous trouverez rapidement que si vous avec un système 4 bits la plupart des multiplications que vous voulez faire donneront un nombre qui ne peut pas être stocké en 4 bits. Donc, quand je vous ai vu prendre des entiers 64 bits (le long non signé est souvent 64 bits) et multiplier quatre fois, ce qui signifie que vous avez besoin de 64 * 5 ou un entier 320 bits pour stocker votre réponse, vous essayiez de mettre cette réponse dans un 64 grand résultat, qui très souvent, selon le compilateur et l'ordinateur fera avec plaisir et tronquera les bits supérieurs vous laissant avec les 64 bits inférieurs de la résultat qui peut facilement paraître plus petit que n'importe lequel de vos opérandes, ce qui est ce que j'avais pensé que vous auriez pu faire au début.
point flottant N'est pas beaucoup plus que la notation scientifique mais en binaire, si vous vouliez multiplier le nombre 1234 et 5678 en utilisant la notation scientifique vous prendriez 1.234*10^3 fois 5.678*10^3 et obtenez 7.007*10^6. Vous gardez votre précision et êtes capable de représenter une gamme plus large de nombres. Je n'entrerai pas dans le fonctionnement en binaire. Mais il ne marche pas travaillez pour votre question originale.
Ahh, la dernière chose à préciser ce que je faisais dans ma question/réponse. Les entiers négatifs en binaire. En raison des relations entre l'addition et la soustraction et les systèmes de base, vous pouvez jouer quelques trucs. Disons que je voulais soustraire 1 du nombre 7 (décimal) en utilisant binaire. Eh bien, il n'y a pas une telle chose comme un circuit de soustraction, vous au lieu d'ajouter un nombre négatif donc au lieu de 7-1 Il est vraiment 7 + (-1), il fait une différence:
0111 + ???? = 0110
quel nombre Pouvez-vous ajouter à 7 pour obtenir 6...en binaire?
0111 + 1111 = 0110
les nombres négatifs en binaire sont appelés "complément de deux", pour faire court, la réponse est "inverser et ajouter 1". Comment représenter moins 1 en binaire? prendre plus un 0001 puis inverser le sens en faisant les uns zéros et les zéros uns (également connu comme les uns complément) 1110 puis Ajouter un 1111. Moins un est un nombre spécial dans les ordinateurs (bien partout) car peu importe combien de bits vous avez il est représenté comme tous les uns. Donc, quand vous voyez quelqu'un faire ceci:
non signé char a;
a = -1;
le compilateur regarde d'abord cela -1 et pense ...11111(binaire), puis il regarde le signe égal et de l'autre côté, oh, vous voulez être de tous, il voit que vous avez un entier signé et non signé mais la conversion est de simplement déplacer les bits au-dessus de sorte que vous dites ci-dessus que vous voulez a = 0xFF; (en supposant un 8 bit char non signé).
Certains compilateurs peuvent se plaindre que vous essayez de stocker un nombre négatif dans un nombre non signé. D'autres compilateurs regarderont cela -1 et le verront comme un 32 bit ou ces jours peut-être 64 bit signé constante entière et puis quand il évalue les égaux dans un 8 bit non signé vous obtiendrez un avertissement que vous ne pouvez pas stocker -1 dans un char signé ou non signé sans une typecast. Mais si vous faites cela:
a = 0; a--;
tous les compilateurs vont aimer ça. et ne vous en plaignez pas, ça brûle juste les cycles de calcul à l'exécution au lieu du temps de compilation.
maintenant quelque part un ami m'a parlé d'un livre qui fait des maths binaires en série. Par exemple pour nier un nombre, habituellement vous faites l'inverse et ad un tour, mais avec le crayon et le papier certains peuvent vous dire l'autre tour. À partir de la copie droite les zéros jusqu'à et y compris les premiers 1 puis inversent après cela, donc moins 2
0010
1110
à partir de la copie droite le 0 puis le premier, puis inverser les bits restants que vous allez à gauche.
moins 6
0110
1010
moins 4
0100
1100
supposément il y a trucs à faire ajouter et soustraire (bien duh, ceux sont faciles) mais aussi multiplier et diviser. Si vous les faites en série alors vous pouvez faire des maths infiniment longues en binaire avec le même alu. Si vous étiez à savoir comment faire que vous pourriez mettre en œuvre que dans le logiciel et votre question originale de multiplier de grandes constantes (avec l'hypothèse de conserver toute la précision) est trivial sur n'importe quel ordinateur.
la réponse que vous avez reçue, 18446744073709551496, est due à votre 999...9s étant tronqué lorsqu'il est affecté à un long long, plus les opérations multiples débordant. Son déterministe, mais effectivement juste une collection aléatoire de bits.
int non signé représente un mot système. Aujourd'hui, ce mot sera maxé à 2^32 -1 ou 2^64 - 1, selon que votre système est 32 ou 64 bits. Vous êtes à la frappe de la pac.
vous devez écrire une classe de bignum ou utiliser un hors du 'net.
Pourquoi faites-vous ce problème de toute façon?
les nombres ne peuvent pas rentrer dans la gamme unsigned long long
donc soit vous pouvez utiliser la bibliothèque GMP ou utiliser la chaîne pour représenter de grands nombres comme je l'ai fait pour le calcul factoriel de nombre comme 50:
#include <cmath>
#include <iostream>
using namespace std;
int main()
{
unsigned int nd, nz;
unsigned char *ca;
unsigned int j, n=50, q, temp;
int i;
double p;
p = 0.0;
for(j = 2; j <= n; j++)
{
p += log10((double)j);
}
nd = (int)p + 1;
ca = new unsigned char[nd+1];
if (!ca)
{
cout << "Could not allocate memory!!!";
exit(0);
}
for (i = 1; (unsigned)i < nd; i++)
{
ca[i] = 0;
}
ca[0] = 1;
p = 0.0;
for (j = 2; j <= n; j++)
{
p += log10((double)j);
nz = (int)p + 1;
q = 0;
for (i = 0;(unsigned) i <= nz; i++)
{
temp = (ca[i] * j) + q;
q = (temp / 10);
ca[i] = (char)(temp % 10);
}
}
cout << "\nThe Factorial of " << n << " is: ";
for( i = nd - 1; i >= 0; i--)
{
cout << (int)ca[i];
}
// delete []ca;
return 0;
}