2010-08-22 2 views
0

Je veux multiplier les nombres longs qui sont donnés dans une base 2^32. J'ai déjà pensé à un bon algorithme pour le faire, mais malheureusement je suis coincé. La situation à laquelle je suis confronté est de savoir comment je multiplie deux longs chiffres et les représente sur la base de 2^32.Comment bien multiplier deux longues longueurs?

#include <stdio.h> 
#include <stdlib.h> 
#include <limits.h> 
typedef unsigned int uint32; 
typedef unsigned long long uint64; 
int main(int argc, char* argv[]) 
{ 

    uint64 a = (uint64)ULONG_MAX; 
    printf("%llu\n", a); 
    uint64 b = (uint64)ULONG_MAX; 
    printf("%llu\n", b); 
    uint64 c = (uint64)(a*b); 

    printf("%llu\n", c); // prints 1. that would be to lower 32 bits of the results. the upper half is 0xFFFFFFFE 

    printf("%llu\n", ULLONG_MAX); 
    system("pause"); 
} 

Pourquoi ULLONG_MAX est-il identique à ULONG_MAX? Selon http://en.wikipedia.org/wiki/Limits.h#Member_constants il devrait être 18,446,744,073,709,551,615 I

Comme vous pouvez le voir dans mes commentaires, je veux le résultat de la multiplikation dans les deux uint32. La moitié inférieure serait 0x1 et la moitié supérieure 0xFFFFFFFE. Comment puis-je obtenir ces valeurs?

(je trouve cette question sur le SO, mais ce n'est pas utile dans ma situation parce que les réponses données ar mes idées similaire: Multiplying two long long ints C)

Edit: Mon système est Windows XP 32 bits. J'utilise 3.4.2 gcc (MinGW-spéciale)

La sortie je reçois pendant l'exécution du code:

4294967295 
4294967295 
1 
4294967295 

Edit2:

printf("%i\n", sizeof(unsigned long)); 
    printf("%i\n", sizeof(unsigned long long)); 

retours

4 
8 

Édition 3: Merci à Petesh j'ai pu trouver la solution:

printf("%lu\n", c & 0xFFFFFFFF); 
    printf("%lu\n", (c >> 32)); 
+1

Quelle implémentation utilisez-vous? Cela fonctionne bien pour moi sur GCC (système 32 bits). Imprime 4294967295, 4294967295, 18446744065119617025, 18446744073709551615 comme prévu. Peut-être que votre implémentation ne supporte pas le format d'impression% llu, le traite comme% lu, et votre système est little-endian alors dans les deux cas, varargs arrive à récupérer le mot moins significatif de l'argument? –

Répondre

5

L'indice est dans le système ("pause") - vous êtes sur Windows? L'impression d'un long temps en utilisant Microsoft Visual C Runtime nécessite l'utilisation de '% I64u' (c'est un i majuscule).

Ceci est basé sur SO question How do you printf an unsigned long long int(the format specifier for unsigned long long int)?

+0

Également nécessaire sur MinGW: http://oldwiki.mingw.org/index.php/long%20long – interjay

+0

Je me suis attendu à cela, une fois que j'ai vu qu'il utilisait Mingw. – Petesh

3

Je ne sais pas pourquoi vous obtenez ces résultats avec votre (non spécifié) compilateur mais gcc sous Ubuntu 10 donne:

4294967295 
4294967295 
18446744065119617025 
18446744073709551615 

avec les les deux derniers étant 0xfffffffe00000001 et (2 -1) respectivement, comme vous le désirez. Alors peut-être envisager de passer à un compilateur plus à jour. Il se peut que vous utilisiez un compilateur pré-C99. Juste par intérêt, qu'est-ce que sizeof (unsigned long) et sizeof (unsigned long long) vous donnent sur votre système. Cela irait un long chemin vers l'explication de votre problème.


Un couple d'autres choses à vérifier depuis votre sizeof s semblent indiquer les types de données eux-mêmes sont d'accord (bien que ceux-ci ne peuvent pas résoudre le problème - ils ont été trouvés avec un fairly shallow web search):

  • Essayez d'utiliser "%I64u" comme chaîne de format au lieu de "%llu". Si MinGW utilise les bibliothèques MSVCRT, cela peut être requis pour le support réel 64 bits printf. Assurez-vous de compiler avec -std=c99.
+0

J'ai ajouté ma version de compilateur – citronas

+0

J'ai édité la taille des lignes de codage dans ma question – citronas

Questions connexes