2

The fortran code below gets segmentation faults. However, when I modify print*,pow(10_8,i) to print*,pow(j,i), it works without vomiting segmentation fault. Why? This is very weird.

module mdl
    implicit none
    integer(kind=8)::n,m=1000000007
    integer(kind=8)::p(1000),k(1000),div(10000000)
contains

    integer(kind=8) function pow(a,pwr)
        implicit none
        integer(kind=8)::a,pwr
        integer(kind=8)::cur
        cur=pwr
        pow=1
        do while(cur>0)
            if(mod(cur,2)==1)pow=mod(pow*a,m)
            a=MOD(a*a,m)
            cur=cur/2
        end do
    end function
end module



program main
    use mdl
    implicit none
    integer(kind=8)::i,j,l,r,x,y
    i=2
    j=10
    print*,pow(10_8,i)
    print*,i
end program
melpomene
  • 84,125
  • 8
  • 85
  • 148
Koreyuki
  • 75
  • 7
  • 1
    compile with all warnings and debug info: `gfortran -Wall -g` with [GCC](http://gcc.gnu.org/) then [use the `gdb` debugger](https://sourceware.org/gdb/current/onlinedocs/gdb/) – Basile Starynkevitch Apr 07 '18 at 06:09
  • 1
    Trying the code with [TIO](https://tio.run/#fortran-gfortran) also gives segmentation fault (with gfortran-7.3.1). I've tried a few options but no useful messages... – roygvib Apr 07 '18 at 07:00
  • Thank you a lot. I tried -Wall option, but I cannot figure out the output messages.Sorry... . By the way, adding value attribute to the parameter 'a', it works correctly. – Koreyuki Apr 07 '18 at 08:28

1 Answers1

3

The problem here is with the argument a of the function pow. In the function the argument a is (potentially) modified on the line

            a=MOD(a*a,m)

The actual argument 10_8 when referencing the function is a literal constant which may not be modified. This is when your program fails. When you use print*,pow(j,i) the j is a variable which may be modified, and your program doesn't fail.

There is a lot of complicated stuff going on here, that I won't fully explain in this answer (you can search for other questions for that). One topic is argument association which explains why you are trying to modify the constant 10_8. However, I'll say something about dummy argument intents.

The dummy argument a has no intent specified. As you intend to use the value of the a as it enters the function and you wish to (potentially) modify it an appropriate intent would be intent(inout). If you apply this, you should find your compiler complain about that assignment line.

Having no intent, such as in the case of the question, is an acceptible thing. This has certain meaning. That is, whether a may be modified depends on whether the actual argument when referencing the function may. When the actual argument is 10_8 it may not; when it is j it may.

The crucial thing is that it isn't the compiler's responsibility, but yours, to check whether the program is doing something here it shouldn't.

Now, you may not want to modify the actual argument j even when you are allowed to. You have a couple of options:

  • you can make a temporary local copy (and mark a as intent(in)), which may be safely modified;
  • you can make an anonymous modifiable copy of the input data using the value attribute.

You do this first with cur=pwr. As an example of the second:

integer(kind=bigint) function pow(a,pwr)
    implicit none
    integer(kind=bigint), value :: a, pwr
    pow=1
    do while(cur>0)
        if(mod(pwr,2)==1)pow=mod(pow*a,m)
        a=MOD(a*a,m)
        pwr=pwr/2
    end do
end function

You now may even mark pow as a pure function.

Finally, if using the value attribute it is required that an explicit interface be available when referencing the function. With the module for the function this is the case here, but this is something to consider in more general cases.

francescalus
  • 30,576
  • 16
  • 61
  • 96