Hi all,
I have implemented exercise above in fortran:
Any suggestions about my coding style or pros and cons?
Hi all,
I have implemented exercise above in fortran:
Any suggestions about my coding style or pros and cons?
Hi @ELNS
in the function fact(n)
, you could write:
integer, intent(in) :: n
integer :: i
The advantage is that if you make a programming error which modifies n
accidentally (imagine you have written do n = 2, i
), the compiler will print that kind of error:
Error: Dummy argument ânâ with INTENT(IN) in variable definition context (assignment) at (1)
And personally I would not indent the else if(n==0) then
and else
lines. My eye could not see immediately and clearly the structure of the algorithm.
In the main program, why putting the i==1 case into the loop ?
Thank you for you valuable tips
As you can see in the example above, the first and second elements of the series are 1 and x itself. I assigned 1.0 to the sum variable by default and then added up value of x itself to sum value in if (i == 1) section of the main program.
As a general rule of thumb, you should always use optional statements like intent
, implicit none
, etc. I guess they are optional only for historical reasons, for the compatibility of old code.
Donât think you lose your time by typing such things: it helps the compiler, and by helping the compiler you are helping yourself. You will save your time (you know, searching a stupid error for 20 minutesâŚ) on the long term.
The compiler can also help you if you add some flags. For example, my favorite flags in gfortran are:
$ gfortran -Wall -Wextra -std=f2003 -pedantic my_program.f90
And if you have several compilers, it can be interesting to compile your program with them. Sometimes a compiler will warn you about something that does not bother the others.
Computing a quotient where the numerator and denominator can both become very large (and possibly overflow) is numerically not recommended.
Writing a program to compute something already available as a built-in intrinsic seems unnecessary. But as a training exercise to learn how to compute other functions expressed as a series, it might be OK.
Here is an alternate version that avoids computing factorials.
program main
implicit none
real(8) :: x, add, e2x
integer(8) :: n, i
print *, "Enter x"
read *, x
n = 2
add = x
e2x = 1. + x
do
add = add*x/n
e2x = e2x + add
if (abs(add/e2x) < tiny(1.0_8)) exit
n = n + 1
end do
print *, n, e2x, exp(x)
end program main
The test (using tiny) is probably too extreme. You might want to explore a more efficient test.
Welcome, Bill!
@ELNS Nice work, keep it up!
I suggest not naming variables using names of intrinsic procedures or other language entities. If you havenât already, youâll notice that Fortran has no reserved words like Fortran does. In your program, you use the name sum
for a local variable, and your IDE gave you a hint. In general this is fine and doesnât break your program, but it:
sum
intrinsic in the same scope. This may not be an issue if you donât intend to use it, but if you find out that you do need it in the same scope, then youâll need to go back and rename all references to your variable.Some alternative names could be total
, sum_of_elements
, summ
, or similar.
Hi @ELNS, please consider the following regarding the coding style:
In your main program you initialize some variables at declaration e.g. integer :: i = 1
, this is bad practice. It implies the save
attribute. In your particular example, there is no side effect, but if you use it inside functions/subroutines or modules it will result in different behavior than expected. As a rule of thumb initialize at declaration if it is a constant variable e.g. integer, parameter :: i = 1
or in case you intentionally need the save
attribute, then explicitly declare it like integer, save :: i = 1
.
A couple of side-notes: It is better to use markdown to post your code instead of a picture, therefore if you need people to help you by testing your code to be as easy as copy-pasting, it is a lot of time-wasting to rewrite oneâs code by looking at a picture. Finally, this post belongs to #help (if a moderator could move it).
Thanks @stavros, I just moved it to âhelpâ.
I understand where youâre coming from but I think itâs a stretch to call it bad practice. In functions and subroutines, of course. In programs and modules, itâs perfectly fine to initialize on declaration and I do so in my book. Rather than hiding the caveats of implied save, I prefer to teach it and make clear how it works head-on and early on. I think every Fortran programmer should learn how implied save works and when they can safely initialize on declaration.
I personally also do not recommend to use integer :: i = 1
. It leads to problems, for example you cannot just copy the code to make it a subroutine, etc. See this issue for a thorough discussion how to fix this in Fortran itself: https://github.com/j3-fortran/fortran_proposals/issues/40, unfortunately so far we havenât found a solution where everybody would agree.
@milancurcic I have to insist that this is a bad practice. Let me elaborate. More often than not, you get new-comers to Fortran from other languages, or new-programmers all together, who are not aware of this behavior. If I receive a code, to work on it (review, modify, maintain⌠etc) from someone that I am not sure of their level of expertise and see initialization at declaration, I will be alarmed, to say the least. On the other hand, if an inexperienced Fortran programmer receives a code with a few variables initialized at declaration without the save
attribute, they will think no more of this, with a high chance of misusing it. If, however, there was the save
attribute, it would have caught their attention, and probably they would be looking for this feature online.
@certik I read (most) of the issue you linked. I have to admit that I do not understand all this hate the save
attribute gets. It can be considered as the equivalent of static
in C/C++, I never heard of the C-community complaining about static
, why do we? The problem is not with the use of save
, rather with its misuse or its no-use that lies on the Fortran design which allows integer :: i = 1
and integer, save :: i = 1
to have the same effect, and unfortunately I do not see an easy way to fix this without breaking backward compatibility. For that reason, and until a permanent solution is given, I consider it a good practice to explicitly use save
or never initialize on declaration.
@stavros we are in agreement. I donât see any hate for the save
attribute. What people donât like is that integer :: i = 1
implies the save
attribute. And as you also noted, and as is discussed in that issue at length, there is no easy fix for that, every proposal that was suggested there has some drawbacks.
@vmagnin @longb @milancurcic @stavros @certik
Thank you all for helping me