2010-07-08 24 views
3

Je suis en train de travailler avec un grand nombre (~ 10^14), et je dois pouvoir les stocker et itérer sur les boucles de cette longueur, soitlong ints en Fortran

n=SOME_BIG_NUMBER 
do i=n,1,-1 

Je J'ai essayé la notation habituelle des étoiles, kind=8 etc. mais rien ne semble fonctionner. Ensuite j'ai vérifié la huge fonction intrinsèque, et le code:

program inttest 

print *,huge(1) 
print *,huge(2) 
print *,huge(4) 
print *,huge(8) 
print *,huge(16) 
print *,huge(32) 

end program inttest 

produit le numéro 2147483647 dans tous les cas. Pourquoi est-ce? J'utilise gfortran (f95) sur une machine 64 bits.

Si je vais avoir besoin d'une bibliothèque bignum, que l'on ne les gens suggèrent?

+0

Est-ce que vous déclarez vos variables comme nombre entier * 8? – Vanya

+4

Itérer sur une boucle ~ 10^14 fois? Est-ce que vous vous rendez compte combien de temps cela pourrait prendre? Je pense que vous devez repenser votre algorithme. –

Répondre

7

Les versions gfortran que j'utilise, 4.3, 4.4 et 4.5 sur un Mac, support des entiers de 8 octets. La meilleure façon de sélectionner un type de variable dans Fortran> = 90 est d'utiliser une fonction intrinsèque pour spécifier la précision dont vous avez besoin. Essayer:

integer, parameter :: LargeInt_K = selected_int_kind (18) 
integer (kind=LargeInt_K) :: i, n 

pour obtenir au moins 18 chiffres décimaux, qui est typiquement un nombre entier de 8 octets. Avec gfortran 4.3, énorme (1_LargeInt_K) produit 9223372036854775807. Lorsque vous avez écrit énorme (1), etc., par défaut la constante était un entier par défaut, ici évidemment 4 octets depuis énorme retourné 2147483647. Donc parfois vous devez Précisez la précision des constantes, pas seulement des variables. Plus communément, cela fait grimper les gens lorsqu'ils perdent des chiffres significatifs sur une constante réelle, qui par défaut est une simple précision.

Voir aussi Fortran: integer*4 vs integer(4) vs integer(kind=4)

Habituellement gfortran a le nom de la commande gfortran. Le f95 pourrait-il être un compilateur différent? Essayez "gfortran -v" et "f95 -v".

+1

Merci. Je n'avais pas réalisé que c'était énorme, mais c'est évident maintenant. Je viens juste de découvrir que mon principal problème n'était pas de diffuser mes littéraux, j'écrirais n = 123456 ... 9 (genre = bla). Écriture n = 12 ... 9_long où long = selected_int_kind (13) fonctionne correctement. – Samizdis

+1

L'une des options d'avertissement à la compilation gfortran vous avertira des constantes qui sont trop volumineuses. Essayez: -fimplicit-aucun -Wall -Wline-troncature -Wcharacter-troncature -Wsurprising -Waliasing -Wimplicit-interface paramètre -Wunused -fcheck = all -fbacktrace pour gfortran 4.5. ou -fbounds-check pour les versions antérieures au lieu de -fcheck-all –

8

Vous avez mal compris la définition précise de la fonction HUGE. HUGE(num) renvoie le plus grand nombre du même type et du même type que num. La valeur renvoyée a également le même type et le même type que num. Comme toutes vos valeurs d'entrée sont des entiers (par défaut) HUGE, renvoie correctement le plus grand nombre entier de taille par défaut.

HUGE(num) ne renvoie pas l'entier le plus grand avec kind=num. HUGE(num) ne renvoie pas non plus le plus grand nombre représentable dans num octets. Alors que de nombreux compilateurs utilisent integer(kind=4) et integer(kind=8)etc pour 4 et 8 octets entiers, ce n'est pas garanti par la norme linguistique et ne peut être invoquée pour être portable.

@ réponse de MSB vous indique comment faire ce que vous voulez, je suis juste aboutement avec quelques éclaircissements.

0

Résumé: Envisagez d'examiner les options du compilateur.

Il a été un l-o-n-g fois depuis que je l'ai fait FORTRAN, et je ne me souviens pas à l'aide ÉNORME(), mais je regarde un peu. Mon ordinateur Linux Intel a gfortran 4.1.2. J'ai trouvé que je devais compiler avec l'option -fdefault-integer-8 activée pour le faire fonctionner pour les entiers 64 bits.Plus précisément, avec le code suivant:

 program inttest 
     print *, huge(1) 
     end program inttest 

exécutant

$ gfortran inttest.for

créé un fichier exécutable qui a imprimé:

2147483647

Toutefois, en cours d'exécution:

$ gfortran -fdefault-integer-8 inttest.for

a donné lieu à un exécutable qui a affiché:

9223372036854775807

Aussi, quand je déclarais une variable entier * 8 et compilé sans l'option -fdefault entier-8, je me suis une erreur. Le code:

program inttest2 
    integer*8 test_int 
    test_int = 9223372036854775807 
    print *, test_int 
    end program inttest2 

course

$ gfortran inttest2.for

a donné lieu à

In file inttest.for:4

test_int = 9223372036854775807 
           1 

Error: Integer too big for its kind at (1)

Cependant, les choses ont fonctionné très bien quand je compilé avec l'option -fdefault entier-8 et je suis un exécutable qui imprimé

9223372036854775807

Peut-être existe-t-il d'autres options pour Gfortran qui seraient utiles, mais je n'ai pas enquêté davantage.

Accordé, cela ne vous aura toujours pas 10^14, mais cela peut aider à expliquer les résultats que vous avez vu.

+0

L'option -fdefault-integer-8 définit l'entier par défaut à 8 octets et n'est pas nécessaire pour pouvoir utiliser des entiers de 8 octets; ils peuvent être obtenus via des déclarations. Le message d'erreur "Erreur: Entier trop grand pour son type à (1)" vous dit que la constante 9223372036854775807 est trop grande pour son genre. Vous n'avez pas besoin de faire le type entier par défaut 8 octets pour résoudre ce problème - vous pouvez spécifier le type de la constante. –

+0

@M. S. B .: Merci pour l'explication. Comment spécifiez-vous le type constant? – GreenMatt

+0

Le type d'une constante est spécifié par un trait de soulignement suivi d'une valeur de type: 9223372036854775807_KindValue. Il est préférable d'utiliser l'intrinsèque selected_int_kind (pour les entiers, ou selected_real_kind pour les réels) pour définir un entier/paramètre "variable" KindValue (voir réponse à cette question) plutôt que de s'appuyer sur une valeur numérique spécifique telle que 8, qui peut varier signification entre les compilateurs. –