2014-04-29 12 views
0

im en utilisant C à l'appel Fortran, mon Fortran appelle tri() méthodeFortran Méthode de tri numérique recipies

*----------------------------------------------------------------------- 
* SUBROUTINE sort(A,n) 
* Subroutine de la librairie "Numerical Recipes" 
* (C) Copr. 1986-92 Numerical Recipes Software 
*----------------------------------------------------------------------- 
     SUBROUTINE sort(arr,n) 
     INTEGER n,M,NSTACK 
     REAL arr(n) 
     PARAMETER (M=7,NSTACK=50) 
     INTEGER i,ir,j,jstack,k,l,istack(NSTACK) 
     REAL a,temp 
     jstack=0 
     l=1 
     ir=n 
1  if(ir-l.lt.M)then 
     do 12 j=l+1,ir 
      a=arr(j) 
      do 11 i=j-1,1,-1 
      if(arr(i).le.a)goto 2 
      arr(i+1)=arr(i) 
11  continue 
      i=0 
2   arr(i+1)=a 
12  continue 
     if(jstack.eq.0)return 
     ir=istack(jstack) 
     l=istack(jstack-1) 
     jstack=jstack-2 
     else 
     k=(l+ir)/2 
     temp=arr(k) 
     arr(k)=arr(l+1) 
     arr(l+1)=temp 
     if(arr(l+1).gt.arr(ir))then 
      temp=arr(l+1) 
      arr(l+1)=arr(ir) 
      arr(ir)=temp 
     endif 
     if(arr(l).gt.arr(ir))then 
      temp=arr(l) 
      arr(l)=arr(ir) 
      arr(ir)=temp 
     endif 
     if(arr(l+1).gt.arr(l))then 
      temp=arr(l+1) 
      arr(l+1)=arr(l) 
      arr(l)=temp 
     endif 
     i=l+1 
     j=ir 
     a=arr(l) 
3  continue 
      i=i+1 
     if(arr(i).lt.a)goto 3 
4  continue 
      j=j-1 
     if(arr(j).gt.a)goto 4 
     if(j.lt.i)goto 5 
     temp=arr(i) 
     arr(i)=arr(j) 
     arr(j)=temp 
     goto 3 
5  arr(l)=arr(j) 
     arr(j)=a 
     jstack=jstack+2 
     if(jstack.gt.NSTACK)pause 'NSTACK too small in sort' 
     if(ir-i+1.ge.j-l)then 
     istack(jstack)=ir 
     istack(jstack-1)=i 
     ir=j-1 
     else 
     istack(jstack)=j-1 
     istack(jstack-1)=l 
     l=i 
     endif 
    endif 
    goto 1 
    END 

Et si je l'appelle la méthode de tri plusieurs fois, j'ai une erreur de segmentation dans cette méthode :(

il est ancien code, mais je suis en confiance parce qu'il vient de recipies numériques mais je me méfie de certaines choses, notamment cette ligne:.

if(jstack.gt.NSTACK)pause 'NSTACK too small in sort' 

Si je suis dans ce cas, mon programme sera en pause? comment est-il possible qu'une méthode de tri le fasse?

Et si cette ligne est suspecte, comment puis-je faire confiance au code entier?

Est-ce que quelqu'un connaît un problème avec ce sous-programme de tri? est-ce que quelqu'un sait une autre méthode pour faire le tri dans Fortran? Parce que je peux remplacer cette méthode de tri par un autre mais je suis nouveau en fortran et je ne peux pas en écrire un autre.

J'ajoute que pas de problème si j'exécute cette méthode en mono thread, mais si je l'exécute en environnement multi thread, le problème est ici. désolé de ne pas mentionné quand j'ai écrit ma question mais je vois cela après l'avoir écrit.

DEBUG informations

current thread: [email protected] 
    [1] __lwp_kill(0x0, 0x6, 0x0, 0x6, 0xffbffeff, 0x0), at 0xff2caa58 
    [2] raise(0x6, 0x0, 0xff342f18, 0xff2aa378, 0xffffffff, 0x6), at 0xff265a5c 
    [3] abort(0x7400, 0x1, 0x0, 0xfcb78, 0xff3413d8, 0x0), at 0xff24194c 
    [4] os::abort(0x1, 0x0, 0xff011084, 0xfefdc000, 0x7d94, 0x7c00), at 0xfee7d3cc 
    [5] VMError::report_and_die(0x0, 0xff038640, 0xff031ff4, 0x1, 0xfee81b94, 0xff031ff4), at 0xfef0cd58 
    [6] JVM_handle_solaris_signal(0xb, 0xacffefe0, 0xacffed28, 0x8000, 0xff030fa0, 0x2013d8), at 0xfea73d48 
    [7] __sighndlr(0xb, 0xacffefe0, 0xacffed28, 0xfea7325c, 0x0, 0x1), at 0xff2c6e78 
    ---- called from signal handler with signal 11 (SIGSEGV) ------ 
    [8] sort_(0xfe2b1350, 0xfe2b135c, 0xfe2b1000, 0x1c00, 0x443bfc7b, 0xfe292484), at 0xfe27e498 
    [9] mediane_(0xa9c1624c, 0xacfff2ac, 0xa9c16060, 0xa9c05c34, 0x0, 0x19), at 0xfe27a38c 


(dbx) frame 8 
0xfe27e498: sort_+0x01d8:  ld  [%l4 + %l1], %f4 
(dbx) disassemble 
0xff2caa58: __lwp_kill+0x0008: bcc,a,pt %icc,__lwp_kill+0x18 ! 0xff2caa68 
0xff2caa5c: __lwp_kill+0x000c: clr  %o0 
0xff2caa60: __lwp_kill+0x0010: cmp  %o0, 91 
0xff2caa64: __lwp_kill+0x0014: move  %icc,0x4, %o0 
0xff2caa68: __lwp_kill+0x0018: retl 
0xff2caa6c: __lwp_kill+0x001c: nop 
0xff2caa70: __lwp_self  : mov  164, %g1 
0xff2caa74: __lwp_self+0x0004: ta  %icc,0x00000008 
0xff2caa78: __lwp_self+0x0008: retl 
0xff2caa7c: __lwp_self+0x000c: nop 

en m solaris avec DBX => gdb sur

je tente d'inspecter adresse, mais ce que je peux taper avoir des informations intéressantes?

Après avoir ajouté l'option -g au compilateur f90, dans dbx je peux voir la valeur ou var et voir le résultat:

[email protected] ([email protected]) terminated by signal ABRT (Abort) 
0xff2caa58: __lwp_kill+0x0008: bcc,a,pt %icc,__lwp_kill+0x18 ! 0xff2caa68 
Current function is sort 
    578   temp=arr(k) 
(dbx) print n 
n = 19 
(dbx) print arr 
arr = 
    (1) 725.0666 
    (2) 741.5034 
    (3) 730.8196 
    (4) 754.3707 
    (5) 741.718 
    (6) 741.718 
    (7) 741.8914 
    (8) 745.9141 
    (9) 744.6705 
    (10) 741.718 
    (11) 745.8358 
    (12) 743.3788 
    (13) 746.2706 
    (14) 746.2706 
    (15) 750.1498 
    (16) 754.3707 
    (17) 754.3707 
    (18) 754.3707 
    (19) 748.2084 
(dbx) print istack 
istack = 
    (1) 7 
    (2) 12 
    (3) 17 
    (4) 18 
    (5) 8 
    (6) 9 
    (7) 1 
    (8) 4 
    (9) 0 
    (10) 0 
    (11) 0 
    (12) 0 
    (13) 0 
    (14) 0 
    (15) 0 
    (16) 0 
    (17) 0 
    (18) 0 
    (19) 0 
    (20) 0 
    (21) 0 
    (22) 0 
    (23) 0 
    (24) 0 
    (25) 0 
    (26) 0 
    (27) 0 
    (28) 0 
    (29) 0 
    (30) 0 
    (31) 0 
    (32) 0 
    (33) 0 
    (34) 0 
    (35) 0 
    (36) 0 
    (37) 0 
    (38) 0 
    (39) 0 
    (40) 0 
    (41) 0 
    (42) 0 
    (43) 0 
    (44) 0 
    (45) 0 
    (46) 0 
    (47) 0 
    (48) 0 
    (49) 0 
    (50) 0 
(dbx) print jstack 
jstack = -31648 
(dbx) 

comment son taht possible jstack un -31648 val! istack n'a que 50 éléments et istack (jstack) me retrun une valeur abd! comment c'est possible? :) merci par avance

+0

Avez-vous essayé de remplacer le 'pause' une déclaration' de write'? L'instruction 'pause' est officiellement supprimée depuis Fortran 95 (mais toujours supportée par de nombreux compilateurs). Quel compilateur utilisez-vous? – Stefan

+0

veuillez exécuter le code dans un débogueur pour pointer une ligne où il se sépare. – Peter

+0

"Est-ce que quelqu'un sait une autre méthode pour faire le tri dans fortran?" Bien sûr, il existe plusieurs méthodes. Écrivez votre propre type de bulle, sorte de tas, type de Shell, peu importe. Ou utilisez 'qsort()' depuis la bibliothèque C standard, comme je le fais souvent. –

Répondre

0

trop grand pour un commentaire:

Malheureusement, la trace de la pile ne montre pas la ligne exacte de l'échec. Quelle est la preuve que l'erreur est à la ligne que vous avez indiquée. Je pourrais imaginer qu'il pourrait y avoir erreur en appelant le système d'exécution, sou vous devriez essayer de changer l'instruction PAUSE à write, read *, ou quelque chose de semblable.

J'ai fait quelques tests avec votre sous-routine dans gfortran:

parameter (n = 100000) 
    dimension b(n) 

    do i=1,1000 
    call random_number(b) 
    call sort(b,n) 
    end do 
end 

avec des tailles de tableau différentes et bornes de boucles. Cela appelle le sort avec de nombreuses entrées différentes. J'ai activé toutes les vérifications et assainissements et n'ai pas rencontré un seul problème.

Edit:

Il fonctionne avec OpenMP aussi:

parameter (n = 100000) 
    real,allocatable :: b(:) 

    !$omp parallel private(b) 
    allocate(b(n)) 
    !$omp do 
    do i=1,1000 
    call random_number(b) 
    call sort(b,n) 
    end do 
    !$omp end do 
    !$omp end parallel 
end 
+0

est-il possible de lancer votre test dans un environnement multi-thread ou non? –

+0

Voir l'édition pour l'exemple multithread. –

+0

Mais attention, pour le multithreading, vous devez utiliser 'récursive subroutine' ou une option du compilateur qui le fait pour vous. –