2016-07-25 5 views
1

J'ai un fichier .bin contenant des pentes et des interceptions. J'utilise Fortran pour lire les valeurs et j'obtiens des valeurs différentes sur les machines exécutant AIX et Linux. Je crois que les données Linux sont exactes. Cela a-t-il quelque chose à voir avec la taille de la pile ou les endiens?Les données du bac sont lues différemment sous AIX et Linux.

Par exemple, la valeur AIX max est: 0.3401589687E + 39 alors que Linux valeur maximale est: 6,031288

program read_bin_files 

REAL :: slope(2500,1250) 
INTEGER :: recl=2500*1250*4 

OPEN(UNIT=8, FILE='MODIS_AVHRR_years_slope.bin', ACTION='READ', ACCESS='direct', FORM='unformatted', RECL=recl, IOSTAT=iostat) 

READ(unit=8, REC = 1, IOSTAT = iostat) slope 
print *, "Max slope value is:", maxval(slope) 

CLOSE(8) 

end 
+0

Pourquoi ne pas utiliser la clause d'accès '' stream' et éviter recl' tous ensemble? Avez-vous accès à un compilateur Fortran moderne (2008+)? Si c'est le cas, utilisez le spécificateur 'newunit'. – jlokimlin

Répondre

1

AIX court (ces jours-ci) sur les processeurs POWER, qui sont habituellement big-endian, alors que Linux est habituellement fonctionne sur x86es, qui sont little-endian. Vous avez donc raison de penser que l'endianisme peut être un problème. Vous déclarez que le résultat de l'exécution de ce programme

program read_bin_files 

    INTEGER*4 :: slope(2500,1250) 
    INTEGER :: recl=2500*1250*4 

    OPEN(UNIT=8, FILE='MODIS_AVHRR_years_slope.bin', ACTION='READ', & 
     ACCESS='direct', FORM='unformatted', RECL=recl) 

    READ(unit=8, REC = 1) slope 

    DO i = 1, 10 
     WRITE(*, '(Z8.8)') slope(1, i) 
    END DO 

    CLOSE(8) 

end 

est le suivant. (« AIX » et « Linux » sont entre guillemets dans les en-têtes de colonnes, car il est la CPU qui importe ici , pas le système d'exploitation.)

"Linux" | "AIX" 
------------+------------ 
3E C2 61 8F | 8F 61 C2 3E 
3E F5 64 52 | 52 64 F5 3E 
BC F3 E0 7E | 7E E0 F3 BC 
BF B9 71 0D | 0D 71 B9 BF 
3E F5 B9 73 | 73 B9 F5 3E 
3F 29 3C 2F | 2F 3C 29 3F 
3E DC C2 09 | 09 C2 DC 3E 
3F 66 86 89 | 89 86 66 3F 
3E 5B 91 A9 | A9 91 5B 3E 
3F 67 73 25 | 25 73 67 3F 

Dans chaque ligne, la moitié droite est le miroir image de la moitié gauche. Cela démontre que le numéro est endianness. Ce que nous ne savons toujours pas, c'est quel ordre d'octets est correct. La réponse à cette question sera presque certainement "l'ordre des octets utilisés par le CPU qui a exécuté le programme que généré le fichier."

Si vous utilisez GNU Fortran, the CONVERT specifier to OPEN devrait résoudre le problème, à condition de pouvoir déterminer le sens de l'interprétation des données. Cependant, je pense c'est une extension. Dans le cas général, je ne connais pas assez FORTRAN pour vous dire quoi faire.

Si vous contrôlez le processus générant ces fichiers de données, vous pouvez éviter l'ensemble du problème à l'avenir en basculant les deux côtés vers un format de données auto-descriptif, tel que HDF.

+0

Sous Linux, les 10 premières valeurs sont: 3EC2618F, 3EF56452, BCF3E07E, BFB9710D, 3EF5B973, 3F293C2F, 3EDCC209,3F668689, 3E5B91A9, 3F677325. Sur AIX, les 10 premiers sont en effet différents: 8F61C23E, 5264F53E, 7EE0F3BC, 0D71B9BF, 73B9F53E, 2F3C293F 09C2DC3E, 8986663F, A9915B3E, 2573673F – kkd92

+0

Merci. Oui, c'est un problème d'endianness. Voir la réponse éditée. – zwol

+0

Merci! Je voulais confirmer le problème et vous avez aidé à le faire. – kkd92

1

Votre machine AIX est probablement un RISC big-endian et votre système Linux est probablement un PC ou une autre plate-forme Intel. Convertissez juste l'endianness.

-je utiliser ces procédures pour 4 octets et 8 variables d'octet (utilisation iso_fortran_env dans le module):

elemental function SwapB32(x) result(res) 
    real(real32) :: res 
    real(real32),intent(in) :: x 
    character(4) :: bytes 
    integer(int32) :: t 
    real(real32) :: rbytes, rt 
    equivalence (rbytes, bytes) 
    equivalence (t, rt) 

    rbytes = x 
    t = ichar(bytes(4:4),int32)  
    t = ior(ishftc(ichar(bytes(3:3),int32),8), t) 
    t = ior(ishftc(ichar(bytes(2:2),int32),16), t) 
    t = ior(ishftc(ichar(bytes(1:1),int32),24), t) 
    res = rt 
end function 

elemental function SwapB64(x) result(res) 
    real(real64) :: res 
    real(real64),intent(in) :: x 
    character(8) :: bytes 
    integer(int64) :: t 
    real(real64) :: rbytes, rt 
    equivalence (rbytes, bytes) 
    equivalence (t, rt) 

    rbytes = x 
    t = ichar(bytes(8:8),int64) 
    t = ior(ishftc(ichar(bytes(7:7),int64),8), t) 
    t = ior(ishftc(ichar(bytes(6:6),int64),16), t) 
    t = ior(ishftc(ichar(bytes(5:5),int64),24), t) 
    t = ior(ishftc(ichar(bytes(4:4),int64),32), t) 
    t = ior(ishftc(ichar(bytes(3:3),int64),40), t) 
    t = ior(ishftc(ichar(bytes(2:2),int64),48), t) 
    t = ior(ishftc(ichar(bytes(1:1),int64),56), t) 
    res = rt 
end function 
utilisation

:

SLOPE = SwapB32(SLOPE) 

Il existe d'autres moyens. Certains compilateurs prennent en charge la norme non-standard OPEN(...,CONVERT='big_endian',... et certains ont des options de ligne de commande telles que -fconvert=big-endian.

0

Cette fonction élémentaire SwapB64 est élégante, et bon à avoir pour ces problèmes. Ou Essayez ces utilisant BIG_ENDIAN, peu endian etc. (Personnellement, je ferais tous les deux)

!OPEN(UNIT=8, FILE='MODIS_AVHRR_years_slope.bin', ACTION='READ', ACCESS='direct', FORM='unformatted', RECL=recl, IOSTAT=iostat) 

OPEN(UNIT=8, FILE='MODIS_AVHRR_years_slope.bin', CONVERT='big_endian', ACTION='READ', ACCESS='direct', FORM='unformatted', RECL=recl, IOSTAT=iostat) 
+0

J'ai effectivement mentionné cela. Le problème avec ceci est que ce spécificateur est complètement en dehors de la norme. Ce n'est pas contre votre réponse, mais je pense que cela devrait être mentionné. –