What is the Basic Structure of a Function in FORTRAN? - c++

This is something that's I've wanted to know recently, mostly out of curiousity. I'm in the mood to learn some old coding styles, and FORTRAN seems like a good place to start.
I guess I should help you guys out by providing a good starting point.
So how would this C procedure be written in FORTRAN?
int foo ( int x , int y )
{
int tempX = x ;
x += y / 2 ;
y -= tempX * 3 ; // tempX holds x's original value.
return x * y ;
}
I know the entire function could be a single line:
return ( x + ( y / 2 ) ) * ( y - ( x * 3 ) ) ;
But the point of me asking this question is to see how those four statements would be written individually in FORTRAN, not neccessarily combined into a single statement.

Don't blame me - you said old coding styles:
C234567
SUBROUTINE FOO(I,J,K)
C SAVE THE ORIGINAL VALUES
IORIG = I
JORIG = J
C PERFORM THE COMPUTATION
I = I + J/2
J = J - IORIG*3
K = I * J
C RESTORE VALUES
I = IORIG
J = JORIG
END SUBROUTINE FOO
I shudder as I write this, but
all variables are implicitly integers, since they start with letters between I and N
FORTRAN passes by reference, so reset I and J at the end to give the same effect as the original function (i.e. pass-by-value, so x and y were unchanged in the calling routine)
Comments start in column 1, actual statements start in column 7
Please, please, please never write new code like this unless as a joke.

Your function might look like this in Fortran
integer function foo(m, n)
integer i
i = m
m = m + n/2
n = n - i*3
foo = m*n
end function foo
You should be able to get started with any tutorial on Fortran. Some thing like this might help http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/fortran.html
cheers

See Functions and Subroutines:
INTEGER FUNCTION foo(i, j)
...
foo = 42
END
then later:
k = foo(1, 2)

Where do you learn FORTRAN from? Just take a look at the wikibooks!
Derived from the example, I'd say:
function func(x, y) result(r)
integer, intent(in) :: x, y
integer :: r
integer :: tempX
tempX = x
x = x / 2
y = y - tempX * 3
r = x * y
end function foo

Similar to above, but with a main program to illustrate how it would be called.
C2345678
program testfoo
implicit none
integer r, foo
r = foo(4,5)
print *, 'result = ', r
end
integer function foo(x,y)
integer x, y
integer tx, ty
tx = x + y / 2
ty = y - x * 3
foo = tx * ty
return
end
Note that this is Fortran 77, which is what I learned 23 years ago.

True old style in applying the rule IJKLMN for integer
C2345678
FUNCTION IFOO(I,J)
II = I + J/2
JJ = J - I*3
IFOO = II*JJ
END

Related

Can't input value in f(x) in this Fortran code?

program prob_1
implicit real*8(a-h, o-z)
f(x) = x**2-cos(x)
df(x) = 2*x+sin(x)
x0 = 0, x1 = 1
do i = 1, 3
if (f((x0+x1)/2) < 0)
x0 = (x0+x1)/2
else
x1 = (x0+x1)/2
end do
print *,"x = ", x
end program
I'm just starting to use Fortran 90.
Now I'm using Code::blocks but I don't know exactly which line the error exists on.
I guess the problem is f((x0+x1)/2) < 0 but don't know actually what is the real error.
what's problem is here?
Be advised that statement functions, the function definitions the OP uses, are obsolescent.
B.3.4 Statement functions
Statement functions are subject to a number of non intuitive restrictions and are a potential source of error because their syntax is easily confused with that of an assignment statement.
The internal function is a more generalized form of the statement function and completely supersedes it.
source: F2018 Standard
Also the notation REAL*8 or anything of that form has never been part of any Fortran standard (see here):
I would suggest to rewrite the code as:
program prob_1
implicit none
double precision :: x1,x0
integer :: i
x0 = 0; x1 = 1
do i = 1, 3
if (f((x0+x1)/2.0D0) < 0) then
x0 = (x0+x1)/2.0D0
else
x1 = (x0+x1)/2.0D0
endif
end do
print *,"x = ", (x0+x1)/2.0D0
contains
function f(x)
double precision, intent(in) :: x
double precision :: f
f = x**2-cos(x)
end function f
function df(x)
double precision, intent(in) :: x
double precision :: df
df = 2.0D0*x+sin(x)
end function df
end program
If you change your program as follows then it will compile:
program prob_1
implicit real*8(a-h, o-z)
f(x) = x**2-cos(x)
df(x) = 2*x+sin(x)
x0 = 0; x1 = 1
do i = 1, 3
if (f((x0+x1)/2) < 0) then
x0 = (x0+x1)/2
else
x1 = (x0+x1)/2
endif
end do
print *,"x = ", x
end program
As mentionned in the comments, you have to add the semicolon ; to separate statements in one line and you have to add the then as well as endif to your if condition.
Hope it helps.

How to plot the Poincaré Section? (Duffing Oscillator)

I've written a program that successfully shows a simple limit cycle for the Duffing equation. However, I now need to plot the Poincaré section for this case.
I need to do this by taking snapshots of the Phase-Space diagram at regular time intervals, such that t*omega = 2*pi*n. As I have omega set to 1 for this case, this is just when t = 2*pi*n. I've attempted this, but am not getting the Poincaré section I expect.
Here's my code:
program rungekutta
implicit none
integer, parameter :: dp = selected_real_kind(15,300)
integer :: i, n
real(kind=dp) z, y, t, A, C, D, B, omega, h
open(unit=100, file="rungekutta.dat",status='replace')
n = 0
!constants
omega = 1.0_dp
A = 0.25_dp
B = 1.0_dp
C = 0.1_dp
D = 1.0_dp
y = 0.0_dp
z = 0.0_dp
t = 0.0_dp
do i=1,1000
call rk2(z, y, t, n)
n = n + 1.0_dp
write(100,*) y, z
end do
contains
subroutine rk2(z, y, t, n) !subroutine to implement runge-kutta algorithm
implicit none
integer, parameter :: dp = selected_real_kind(15,300)
integer, intent(inout) :: n
real(kind=dp) :: k1y, k1z, k2y, k2z, y, z, t, pi
pi = 4.0*ATAN(1.0)
h = 0.1_dp
t = n*2*pi
k1y = dydt(y,z,t)*h
k1z = dzdt(y,z,t)*h
k2z = dzdt(y + (0.5_dp*k1y), z + (0.5_dp*k1z), t + (0.5_dp*h))*h
k2y = dydt(y, z +(0.5_dp*k1z), t)*h
y = y + k2y
z = z + k2z
end subroutine
!2nd order ODE split into 2 for coupled Runge-Kutta, useful to define 2
functions
function dzdt(y,z,t)
real(kind=dp) :: y, z, t, dzdt
dzdt = -A*y**3.0_dp + B*y - C*z + D*sin(omega*t)
end function
function dydt(y,z,t)
real(kind=dp) :: z, dydt, y, t
dydt = z
end function
end program
I have also attached an image of what my Poincaré section looks like:
.
This is y on the x axis vs dydt.
And an image of what I'd expect:
In your rk2 routine you perform one step of step length 0.1. Thus the plot is the full trajectory of the solution at that resolution. However the intend seems to be to integrate over a full period length. This would require a loop in that routine.
In other words, what you want is the plot of (y(n*T), z(n*T)) where T is one of the periods of the system, per your code T=2*p. What you actually compute is (y(n*h), z(n*h)) where h=0.1 is the step size of a single step of RK2.
Also the arguments of k2y need to be corrected as per the comment of user5713492
With a corrected integrator you should get something like the following picture:
where the red squares are the points at t=n*2*pi. The indicated step size by the dots on the solution curve is the same h=0.1, the integration is over t=0..300.
def RK2(f,u,times,subdiv = 1):
uout = np.zeros((len(times),)+u.shape)
uout[0] = u;
for k in range(len(times)-1):
t = times[k]
h = (times[k+1]-times[k])/subdiv
for j in range(subdiv):
k1 = f(u,t)*h
k2 = f(u+0.5*k1, t+0.5*h)*h
u, t = u+k2, t+h
uout[k+1]=u
return uout
def plotphase(A,B,C,D):
def derivs(u,t): y,z = u; return np.array([ z, -A*y**3 + B*y - C*z + D*np.sin(t) ])
N=60
u0 = np.array([0.0, 0.0])
t = np.arange(0,300,2*np.pi/N);
u = RK2(derivs, u0, t, subdiv = 10)
plt.plot(u[:-2*N,0],u[:-2*N,1],'.--y', u[-2*N:,0],u[-2*N:,1], '.-b', lw=0.5, ms=2);
plt.plot(u[::N,0],u[::N,1],'rs', ms=4); plt.grid(); plt.show()
plotphase(0.25, 1.0, 0.1, 1.0)

How to calculate Pi using Monte Carlo Simulation?

I'm attempting to write a FORTRAN 90 program that calculates Pi using random numbers. These are the steps I know I need to undertake:
Create a randomly placed point on a 2D surface within the range [−1, 1] for x and y, using call random_number(x).
calculate how far away the point is from the origin, i'll need to do both of these steps for N points.
for each N value work out the total amount of points that are less than 1 away from origin. Calculate pi with A=4pir^2
use a do loop to calculate pi as a function of N and output it to a data file. then plot it in a graphing package.
This is what I have:
program pi
implicit none
integer :: count, n, i
real :: r, x, y
count = 0
CALL RANDOM_SEED
DO i = 1, n
CALL RANDOM_NUMBER(x)
CALL RANDOM_NUMBER(y)
IF (x*x + y*Y <1.0) count = count + 1
END DO
r = 4 * REAL(count)/n
print *, r
end program pi
I know i've missed out printing the results to the data file, i'm not sure on how to implement this.
This program gives me a nice value for pi (3.149..), but how can I implement step 4, so that it outputs values for pi as a function of N?
Thanks.
Here is an attempt to further #meowgoesthedog effort...
Program pi
implicit none
integer :: count, n, i
real :: r, x, y
count = 0
Integer, parameter :: Slice_o_Pie = 8
Integer :: Don_McLean
Logical :: Purr = .FALSE.
OPEN(NEWUNIT=Don_McLean, FILE='American.Pie')
CALL RANDOM_SEED
DO i = 1, n
CALL RANDOM_NUMBER(x)
CALL RANDOM_NUMBER(y)
IF (x*x + y*Y <1.0) count = count + 1
Purr = .FALSE.
IF(MODULO(I, Slice_o_Pie) == 0) Purr = .TRUE.
IF (Purr) THEN
r = 4 * REAL(count)/i
print *, i, r
WRITE(LUN,*) 'I=',I,'Pi=',Pi
END IF
END DO
CLOSE(Don_McLean)
end program pi
Simply put the final calculation step inside the outer loop, and replace n with i. Also maybe add a condition to limit the number of results printed, e.g. i % 100 = 0 to print every 100 iterations.
program pi
implicit none
integer :: count, n, i
real :: r, x, y
count = 0
CALL RANDOM_SEED
DO i = 1, n
CALL RANDOM_NUMBER(x)
CALL RANDOM_NUMBER(y)
IF (x*x + y*Y <1.0) count = count + 1
IF ([condition])
r = 4 * REAL(count)/i
print *, i, r
END IF
END DO
end program pi

Program For Calculating Sin Using Taylor Expansion Not Working?

I'm trying to write some code that'll calculate the value of sin(0.75) using the Taylor expansion, and print each iteration until the absolute difference between the value calculated using the expansion, and the value calculated using Fortran's intrinsic sin function is less than 1E-6. Here is my code:
program taylor
implicit none
real :: x = 0.75
do while (x - sin(0.75) < 10**(-6))
print *, x
x = x - ((x**3)/6) + ((x**5)/120) - ((x**7)/5040)
end do
end program taylor
However, this doesn't print anything out? Why is this?
It looks too obvious to most people so no-one even wanted to answer, but it should be said explicitly
The condition x - sin(0.75) < 10**(-6) is obviously not true when x very different from sin(0.75), so the do while loop is never entered.
Also, as IanH commented 10**(-6) will give 0 because the result of the power of two integers is again an integer. The literal real number 10^-6 should be expressed as 1e-6.
If you change it to x - sin(0.75) > 1e-6 the loop will proceed, but it will run forever, because your iteration is wrong. Taylor series works differently, you should compute
y = 0
y = y + x**1/1!
y = y - x**3/3!
y = y + x**5/5!
y = y - x**7/7!
...
and so on, which is a very different kind of loop.
Try this one:
program taylor
implicit none
real :: x = 0.75
real :: y, fact
integer :: sgn, i
fact = 1
sgn = 1
y = 0
do i = 1, 10, 2
y = y + sgn * x**i / fact
fact = fact*(i+1)*(i+2)
sgn = -sgn
end do
print *, y, sin(x)
end program taylor

Program to calculate sin(0.75) close, but not working?

I have already posted a question regarding this problem, and have implemented what i've learned from the answers. I'm now at a point where the answers that are printed out on the screen are very close, but incorrect. Here is the code I now have:
program taylor
implicit none
integer :: k = 0
real :: y = 0.75
real :: x = 0.75
do while (abs(y - sin(0.75)) > 1E-6)
k = k + 1
y = y + ((y * (-x * x)) /( 2 * k * (2 * k + 1 )))
print *, y
end do
end program taylor
I can't seem to spot the error here, why is this not working? The first answer it prints is correct, but then it seems to get progressively lower, instead of closer to the true value. (The do while loop is to ensure the program stops when the absolute value between the calculation and the intrinsic sin function is less than 1E-6). I can see that the program is constantly reducing the final output, and the Taylor series is suppose to alternate between - and +, so how can I write that in my program?
Thanks.
The taylor series uses factorials and power of x.
taylor_sin(x) = sum[0->n] ( [(-1 ^ n) / (2n + 1)!] * x**(2n + 1) )
(Sorry for my poor keyboard math skills...)
program taylor
implicit none
integer :: n = 0
real :: fac = 1
real :: y = 0.75
real :: x = 0.75
real :: px = 1
integer :: sgn = -1
integer :: s = 1
do while (abs(y - sin(0.75)) > 1E-6)
n = n + 1
fac = fac * (2 * n) * ((2 * n) + 1)
px = px * (x * x)
s = s * sgn
y = y + ((s /fac) * (px * x))
print *, y
end do
end program taylor
Computing the factorial fac in a loop is rather trivial.
To compute x**(2n + 1), compute and keep x**(2n) and add an extra multiplication by x.
I use an integer to compute -1**n since using a real may lose precision over time.
[EDIT] silly me... you can save that extra multiplication by x by setting px to 0.75 before the loop.