Est-ce que MINLOC fonctionne pour les tableaux commençant à l’indice 0? (Fortran 90/95)

Après avoir utilisé C pendant un moment, je suis retourné à Fortran et ai alloué les tableaux de mon code d’index 0 à N:

real(kind=dp), dimension(:), allocatable :: a allocate(a(0:50)) 

J’avais besoin de trouver l’index de la valeur absolue minimale du tableau. J’ai donc utilisé MINLOC, et pour vérifier cela, je l’ai comparé à MINVAL:

 minloc(abs(a(:))) minval(abs(a)) 

Le résultat de MINLOC était l’indice 42 mais le résultat de MINVAL correspondait à 41 . Voici la section pertinente de la sortie:

 Index ia(i) 39 0.04667 40 0.02222 41 0.00222 !This was clearly the minimum value 42 0.02667 MINLOC = 42 MINVAL = 0.00222 

Je suppose que cela a quelque chose à voir avec le comportement insortingnsèque de Fortran qui ne gère pas correctement les tableaux d’indice 0, car ce n’est pas le style Fortran standard de déclarer des tableaux de cette manière (mais cela est toujours autorisé!).

Quelqu’un peut-il confirmer cela ou proposer une solution de contournement?

Votre tableau a commence effectivement à l’index 0, mais vous ne l’avez pas utilisé. Vous avez cherché un minimum de tableau abs(a(:)) . Cette expression de tableau anonyme commence à 1 comme tous les tableaux le font par défaut.

Mais même si vous utilisiez a le résultat serait le même et cohérent avec le fonctionnement des arguments de tableau dans Fortran.

La norme Fortran stipule clairement:

L’indice i renvoyé est compris entre 1 et ei, où ei est l’étendue de idimension de ARRAY. Si ARRAY a la taille zéro, tous les éléments du résultat sont nuls.

Les limites inférieures ne sont pas automatiquement transmises au tableau si vous avez utilisé des arguments de forme supposés. Par exemple si vous avez votre propre fonction

  function f(arg) real :: arg(:) 

arg commence toujours à 1, peu importe où l’argument actuel a commencé dans le code appelant.

Vous pouvez le changer pour commencer à une autre valeur

  function f(arg) real :: arg(-42:) 

et il serait indexé à partir de cette valeur.

Il existe deux méthodes simples pour gérer la complication d’ajustement des index obtenus avec minloc (): l’une consiste simplement à append lbound () – 1 pour tous les index et l’autre à utiliser un pointeur de tableau avec des index basés sur 1. Un exemple de code peut ressembler à ceci:

 program test implicit none integer, allocatable, target :: a(:,:) integer, pointer :: anew(:,:) integer :: loc(2) allocate( a( 0:4, 2:5 ), source= 10 ) !! make an array filled with 10 a( 2, 3 ) = -700 !! set the minimum value loc(:) = minloc( a ) !! minloc() receives "a" with 1-based indices print *, loc(:) !! so we get [3,2] print *, a( loc(1), loc(2) ) !! 10 (wrong result...) !! Method (1) : adjust indices manually loc(:) = loc(:) + lbound( a ) - 1 print *, a( loc(1), loc(2) ) !! -700 (now a correct result) !! Method (2) : use array pointer with 1-based indices anew( 1:, 1: ) => a loc(:) = minloc( anew ) print *, loc(:) !! we get [3,2] again print *, anew( loc(1), loc(2) ) !! -700 (this time, no need to adjust indices) end program