I’m trying to implement the fibonacci solution using iterative method. It all works well except that the tmp variable remembers the values of temporary variables for the next function call.
Here’s the code that I’ve written
program fibonacci
use, intrinsic :: iso_fortran_env, only : i8=>int64, error_unit
implicit none
integer :: n=5
integer(i8) :: f1, f2
print *, fib(n), fib(n), fib(n)
print *, fib(n)
contains
function fib(n) result(f) ! iterative
integer,intent(in) :: n
integer(i8) :: f
integer(i8) :: tmp=0, f_1=1
integer :: i=0
if (n <= 0) then
write(error_unit, *) 'n must be a positive integer'
stop 1
end if
f=f_1
do i = 2, n
tmp=f
f = f + f_1
f_1 = tmp
end do
end function fib
end program fibonacci
This gives the following output.
8 40 200
1000
It looks like the tmp and f_1 are remembering the values between function calls. What am I doing wrong here? Isn’t it supposed to remember the variable values only if save is mentioned? Please let me know.
Thanks in advance!
Setting a variable equal to a value in the type declaration statement implicitly gives the variable the SAVE attribute. In this regard, the behavior of local variables is different from the behavior of corresponding variables in languages such as C.
You should initialize variables in the declaration only if they are constants (PARAMETER), or if you are conscious it implies SAVE (but in that case explicit is better than implicit…)
Thank you! It seems the latest gfortran doesn’t support this yet. Is there any specific advantage in calling elemental instead of normal recursive function? Also, is there any resource for reading about these changes?
What version of gfortran? All the versions I’ve used in the past five years or so support recursive procedures. If you have a somewhat older version, you may have to add the “recursive” attribute explicitly, i.e, recursive function fibonacci(n). Procedures being recursive by default is a relatively recent change in the language.
For a brief overview of new features in each standard, I like John Reid’s writeups:
If you encounter a features that isn’t there, it’s likely from Fortran 95 or earlier, in which case the Wikipedia page is pretty comprehensive: Fortran 95 language features - Wikipedia
Since LFortran has not yet implemented the implicit save mis-feature of Fortran, it gives the results an uninitiated Fortran programmer would expect for the slightly modified program
program fibonacci
use, intrinsic :: iso_fortran_env, only : i8=>int64
implicit none
integer :: n=5
integer(i8) :: f1, f2
print *, fib(n), fib(n), fib(n)
print *, fib(n)
contains
function fib(n) result(f) ! iterative
integer,intent(in) :: n
integer(i8) :: f
integer(i8) :: tmp=0, f_1=1
integer :: i=0
if (n <= 0) then
write(*,*) 'n must be a positive integer'
stop 1
end if
f=f_1
do i = 2, n
tmp=f
f = f + f_1
f_1 = tmp
end do
end function fib
end program fibonacci
Ouput:
8 8 8
8
Every compiler has a strict-standard mode, and in that mode LFortran is obliged to give the results produced with implicit save. Maybe the default mode should refuse to compile the program unless the save attribute is added explicitly.
I’m currently on 11.2.1. Yes, I did intend to meant the recursive by default procedures. Seems only intel compiler supports that for now. Thank you very much for the links!
Implicit save strikes again! I firmly believe that if this stupid feature is removed from the language (and replaced with the expected behavior) it will fix more bugs than it will cause.
I agree. However, considering how difficult, uncertain and lengthy this process would be, more pragmatically we should in parallel lobby compiler vendors to offer a switch linked to a flag.
Yet another time, LFortran does the right thing™ by default: kudos.
In rare cases (this is one of them) it may be worthwhile to delete a feature from the language, but changing what legal code does causes errors and confusion. It’s not hard to write
integer :: i
i = 0
Maybe Fortran could add an init attribute so that integer, init :: i = 0, j = 1
means the same as
integer :: i,j
i = 0
j = 1
with the ability to change i and j later. So the user could only give a value to a variable within a declaration if the save, parameter, or init attribute appeared. Maybe init is not the right word, but the idea is that the user is required to say what he means.
The flooring behavior of integer division often bites Fortran programmers, and starting from scratch, I’d prefer that 1/2 = 0.5 rather than 0 in Fortran, but Fortran is not Python (which changed the behavior of integer division).
I think that breaking such a “feature” is not a big deal, since I doubt it was used a lot. Except cases when it was used by mistake, so deleting could actually fix some hidden bugs!
Thanks @Beliavsky for checking LFortran. Indeed, it is a “bug” in LFortran that it actually works as expected. But I am happy that it can actually compile it, we made huge progress lately.
@jacobwilliams will be pleased that we will have to “fix” this “bug” and actually introduce the save attribute.
Or do we?
What would you like LFortran to do?
I have a feeling, as noted by others before, that when any Fortran code actually has integer :: i=0, it is a bug in the code, it was not meant to add the save attribute.
I would like the default mode in LFortran to be the “strict” mode: Create pedantic/strict mode (#450) · Issues · lfortran / lfortran · GitLab, in there it’s already specified that “implied save” (the issue above) would not be allowed. So it would just refuse to compile it, with a very helpful error message how to fix it.
I think the best we can hope for as far as the standard is concerned (at least as long as backward compatibility at all cost rules the committee) is that this feature is deleted from the standard. Then it gets flagged as a syntax error when you use the standard conforming compile flag. So we give up any hope of using this syntax for anything else.
If it was up to me, we would change the behavior to be what everyone expects: to be equivalent to a declaration and a normal assignment. It’s a very natural syntax for that, and makes perfect sense for people coming in from other languages. Like I say, this would fix more bugs than it causes. I see it over and over again, year after year after year, people getting bitten by this dumb implicit save behavior. I have never seen anyone use it on purpose.