Here is the Main Program:
PROGRAM integration
EXTERNAL funct
DOUBLE PRECISION funct, a , b, sum, h
INTEGER n, i
REAL s
PARAMETER (a = 0, b = 10, n = 200)
h = (b-a)/n
sum = 0.0
DO i = 1, n
sum = sum+funct(i*h+a)
END DO
sum = h*(sum-0.5*(funct(a)+funct(b)))
PRINT *,sum
CONTAINS
END
And below is the Function funct(x)
DOUBLE PRECISION FUNCTION funct(x)
IMPLICIT NONE
DOUBLE PRECISION x
INTEGER K
Do k = 1,10
funct = x ** 2 * k
End Do
PRINT *, 'Value of funct is', funct
RETURN
END
I would like the 'Sum' in the Main Program to print 10 different sums over 10 different values of k in Function funct(x).
I have tried the above program but it just compiles the last value of Funct() instead of 10 different values in sum.
Array results require an explicit interface. You would also need to adjust funct and sum to actually be arrays using the dimension statement. Using an explicit interface requires Fortran 90+ (thanks for the hints by #francescalus and #VladimirF) and is quite tedious:
PROGRAM integration
INTERFACE funct
FUNCTION funct(x) result(r)
IMPLICIT NONE
DOUBLE PRECISION r
DIMENSION r( 10 )
DOUBLE PRECISION x
END FUNCTION
END INTERFACE
DOUBLE PRECISION a , b, sum, h
DIMENSION sum( 10)
INTEGER n, i
PARAMETER (a = 0, b = 10, n = 200)
h = (b-a)/n
sum = 0.0
DO i = 1, n
sum = sum+funct(i*h+a)
END DO
sum = h*(sum-0.5*(funct(a)+funct(b)))
PRINT *,sum
END
FUNCTION funct(x)
IMPLICIT NONE
DOUBLE PRECISION funct
DIMENSION funct( 10)
DOUBLE PRECISION x
INTEGER K
Do k = 1,10
funct(k) = x ** 2 * k
End Do
PRINT *, 'Value of funct is', funct
RETURN
END
If you can, you should switch to a more modern Standard such as Fortran 90+, and use modules. These provide interfaces automatically, which makes the code much simpler.
Alternatively, you could take the loop over k out of the function, and perform the sum element-wise. This would be valid FORTRAN 77:
PROGRAM integration
c ...
DIMENSION sum( 10)
c ...
INTEGER K
c ...
DO i = 1, n
Do k = 1,10
sum(k)= sum(k)+funct(i*h+a, k)
End Do
END DO
c ...
Notice that I pass k to the function. It needs to be adjusted accordingly:
DOUBLE PRECISION FUNCTION funct(x,k)
IMPLICIT NONE
DOUBLE PRECISION x
INTEGER K
funct = x ** 2 * k
PRINT *, 'Value of funct is', funct
RETURN
END
This version just returns a scalar and fills the array in the main program.
Apart from that I'm not sure it is wise to use a variable called sum. There is an intrinsic function with the same name. This could lead to some confusion...
Related
Here is the Main Program:
PROGRAM integration
EXTERNAL funct
DOUBLE PRECISION funct, a , b, sum, h
INTEGER n, i
REAL s
PARAMETER (a = 0, b = 10, n = 200)
h = (b-a)/n
sum = 0.0
DO i = 1, n
sum = sum+funct(i*h+a)
END DO
sum = h*(sum-0.5*(funct(a)+funct(b)))
PRINT *,sum
CONTAINS
END
And below is the Function funct(x)
DOUBLE PRECISION FUNCTION funct(x)
IMPLICIT NONE
DOUBLE PRECISION x
INTEGER K
Do k = 1,10
funct = x ** 2 * k
End Do
PRINT *, 'Value of funct is', funct
RETURN
END
I would like the 'Sum' in the Main Program to print 10 different sums over 10 different values of k in Function funct(x).
I have tried the above program but it just compiles the last value of Funct() instead of 10 different values in sum.
Array results require an explicit interface. You would also need to adjust funct and sum to actually be arrays using the dimension statement. Using an explicit interface requires Fortran 90+ (thanks for the hints by #francescalus and #VladimirF) and is quite tedious:
PROGRAM integration
INTERFACE funct
FUNCTION funct(x) result(r)
IMPLICIT NONE
DOUBLE PRECISION r
DIMENSION r( 10 )
DOUBLE PRECISION x
END FUNCTION
END INTERFACE
DOUBLE PRECISION a , b, sum, h
DIMENSION sum( 10)
INTEGER n, i
PARAMETER (a = 0, b = 10, n = 200)
h = (b-a)/n
sum = 0.0
DO i = 1, n
sum = sum+funct(i*h+a)
END DO
sum = h*(sum-0.5*(funct(a)+funct(b)))
PRINT *,sum
END
FUNCTION funct(x)
IMPLICIT NONE
DOUBLE PRECISION funct
DIMENSION funct( 10)
DOUBLE PRECISION x
INTEGER K
Do k = 1,10
funct(k) = x ** 2 * k
End Do
PRINT *, 'Value of funct is', funct
RETURN
END
If you can, you should switch to a more modern Standard such as Fortran 90+, and use modules. These provide interfaces automatically, which makes the code much simpler.
Alternatively, you could take the loop over k out of the function, and perform the sum element-wise. This would be valid FORTRAN 77:
PROGRAM integration
c ...
DIMENSION sum( 10)
c ...
INTEGER K
c ...
DO i = 1, n
Do k = 1,10
sum(k)= sum(k)+funct(i*h+a, k)
End Do
END DO
c ...
Notice that I pass k to the function. It needs to be adjusted accordingly:
DOUBLE PRECISION FUNCTION funct(x,k)
IMPLICIT NONE
DOUBLE PRECISION x
INTEGER K
funct = x ** 2 * k
PRINT *, 'Value of funct is', funct
RETURN
END
This version just returns a scalar and fills the array in the main program.
Apart from that I'm not sure it is wise to use a variable called sum. There is an intrinsic function with the same name. This could lead to some confusion...
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
I have already current code, but it still not working. If code is correct, please help how I can compile it. I had tried it to compile so:
gfortran trap.f -fopenmp
PROGRAM TRAP
USE OMP_LIB
DOUBLE PRECISION INTEG, TMPINT
DOUBLE PRECISION A, B
PARAMETER (A=3.0, B=7.0)
INTEGER N
PARAMETER (N=10)
DOUBLE PRECISION H
DOUBLE PRECISION X
INTEGER I
DOUBLE PRECISION F
H = (B-A)/N
INTEG = 0.0
TMPINT = 0.0
!$omp parallel firstprivate(X, TMPINT) shared(INTEG)
!$omp do
DO 10 I=1,N-1,1
X=A+I*H
TMPINT = TMPINT + F(X)
10 CONTINUE
!$omp end do
!$omp critical
INTEG = INTEG + TMPINT
!$omp end critical
!$omp end parallel
NTEG = (INTEG+(F(A)+F(B))/2.0)*H
PRINT *, "WITH N=", N, "INTEGRAL=", INTEG
END
FUNCTION F(X)
DOUBLE PRECISION X
F = X / (X + 1) * EXP(-X + 2)
END
Compiler gives following problems:
[http://i.stack.imgur.com/QPknv.png][1]
[http://i.stack.imgur.com/GYkmN.png][2]
Your program has a suffix .f, so gfortran assumes that the code is in fixed format and complains that many statements are "unclassifiable". To fix this, change the file name to trap.f90 and compile as gfortran -fopenmp trap.f90 to assume free format. There are also other problems: one is that the return type of function F(X) does not match with the type declared in the main program, so F(X) needs to be modified as
FUNCTION F(X)
implicit none !<--- this is always recommended
DOUBLE PRECISION X, F !<--- add F here
F = X / (X + 1) * EXP(-X + 2)
END
Another issue is that NTEG is probably a typo of INTEG, so it should be modified as
INTEG = (INTEG+(F(A)+F(B))/2.0)*H
(this is automatically detected if we have implicit none in the main program). Now running the code with, e.g. 8 threads, gives
$ OMP_NUM_THREADS=8 ./a.out
WITH N= 10 INTEGRAL= 0.28927708626319770
while the exact result is 0.28598... Increasing the value of N, we can confirm that the agreement becomes better:
WITH N= 100 INTEGRAL= 0.28602065571967972
WITH N= 1000 INTEGRAL= 0.28598803555916535
WITH N= 10000 INTEGRAL= 0.28598770935198736
WITH N= 100000 INTEGRAL= 0.28598770608991503
BTW, it is probably easier to use the reduction clause to do the same thing, for example:
INTEG = 0.0
!$omp parallel do reduction(+ : integ) private(x)
DO I = 1, N-1
X = A + I * H
INTEG = INTEG + F( X )
ENDDO
!$omp end parallel do
INTEG = (INTEG+(F(A)+F(B))/2.0)*H
Your code is in fixed form (.f). Therefore, you must code by the rules of the fixed format: The first six characters on each line have a special meaning and should be blank unless you specify a comment in the first position, a line continuation (sixth position), or statement labels 10.
If you format your code accordingly, the compiler complains about a mismatch in the return value of F(X). As you do not use implicit none, the type is defined by the first letter of the function, and F maps to a (single precision) real. So you need to specify the return type explicitly.
Then the code looks like:
PROGRAM TRAP
USE OMP_LIB
DOUBLE PRECISION INTEG, TMPINT
DOUBLE PRECISION A, B
PARAMETER (A=3.0, B=7.0)
INTEGER N
PARAMETER (N=10)
DOUBLE PRECISION H
DOUBLE PRECISION X
INTEGER I
DOUBLE PRECISION F
H = (B-A)/N
INTEG = 0.0
TMPINT = 0.0
c$omp parallel firstprivate(X, TMPINT) shared(INTEG)
c$omp do
DO 10 I=1,N-1,1
X=A+I*H
TMPINT = TMPINT + F(X)
10 CONTINUE
c$omp end do
c$omp critical
INTEG = INTEG + TMPINT
c$omp end critical
c$omp end parallel
INTEG = (INTEG+(F(A)+F(B))/2.0)*H
PRINT *, "WITH N=", N, "INTEGRAL=", INTEG
END
DOUBLE PRECISION FUNCTION F(X)
DOUBLE PRECISION X
F = X / (X + 1) * EXP(-X + 2)
END
[Please note that I also fixed the NTAG = line into INTEG= as I believe this is intended. I did not check the code for validity. ]
I'm having some troubles to calcule the integral of e^x inside and interval [b.a] using fortran.
I think I'm doing something wrong in the funcion calls. Thanks for helping me.
program trapezium
implicit none
integer :: i, n, b, a
real :: sumation, mean, deltax, f(i), integral
! The value of the integral using the trapezium rule can be found using
! integral = (b - a)*((f(a) +f(b))/2 + sumation_1_n-1 )/n
write(*,*) "type the limits b, a and the number of intervals"
read *, b, a, n
deltax = (b - a)/n
mean = (f(a) + f(b))/2
sumation = 0
do i = 1, n-1
sumation = sumation + f(i)
end do
integral = deltax*(mean + sumation)
write (*,*) "the value of the integral using the trapezoidal method is", integral
end program
function f(x)
real :: f(x)
integer :: x
f(x) = EXP(x)
end function
There are a couple of issues with your code:
f is a function, but at the same time you define an array f(i)
When defining an array of fixed size, the size has to be known at compile time. So real :: f(i) is only valid for a constant i
exp() expects a real variable, not an integer
Integer arithmetic might lead to unexpected results: 1/2 = 0 and not 0.5!
What about (This does not try to fix the maths, though - see my comment):
module functions
contains
function f(x)
implicit none
real :: f
integer,intent(in) :: x
f = EXP(real(x))
end function
end module
program trapezium
use functions
implicit none
integer :: i, n, b, a
real :: sumation, mean, deltax, integral
! The value of the integral using the trapezium rule can be found using
! integral = (b - a)*((f(a) +f(b))/2 + sumation_1_n-1 )/n
write(*,*) "type the limits b, a and the number of intervals"
read *, b, a, n
deltax = real(b - a)/real(n)
mean = (f(a) + f(b))/2
sumation = 0
do i = 1, n-1
sumation = sumation + f(i)
end do
integral = deltax*(mean + sumation)
write (*,*) "the value of the integral using the trapezoidal method is", integral
end program
Note that the use of modules enables the compiler to check for the arguments of the function. Additionally, you do not need to define the return value of the function in the main program.
I am new in Fortran and i have this problem.
When i ran this DO is ok:
integer, parameter :: Int10Type = selected_int_kind (10)
INTEGER (Int10Type), PARAMETER :: TOTAL_TIME = 1000, TOTAL_INI = 200
INTEGER (Int10Type):: t, z
REAL (16), DIMENSION(TOTAL_Z, TOTAL_TIME) :: current
DO t = 1, TOTAL_TIME
current(TOTAL_Z, t) = TEMP_INI
END DO
DO t = 1, TOTAL_TIME - 1
DO z = 2, (TOTAL_Z - 1)
current(z, t + 1) = current (z, t) + KAPPA*DELTA_T*((current(z - 1, t) -2.0*current(z, t) + current(z + 1, t)) / DELTA_Z**2)
END DO
END DO
But, when i increment var limite
integer, parameter :: Int10Type = selected_int_kind (10)
INTEGER (Int10Type), PARAMETER :: TOTAL_TIME = 1000000000, TOTAL_INI = 200
INTEGER (Int10Type):: t, z
REAL (16), DIMENSION(TOTAL_Z, TOTAL_TIME) :: current
DO t = 1, TOTAL_TIME
current(TOTAL_Z, t) = TEMP_INI
END DO
DO t = 1, TOTAL_TIME - 1
DO z = 2, (TOTAL_Z - 1)
current(z, t + 1) = current (z, t) + KAPPA*DELTA_T*((current(z - 1, t) -2.0*current(z, t) + current(z + 1, t)) / DELTA_Z**2)
END DO
END DO
The output of the program is 'killed'
Why? what i do bad?
integer(10) means integer(kind=10), not an integer with at least 10 decimal digits. It is up to a compiler what kind=10 means. There is no guarantee that kind=10 even exists! If you want to specify 10 decimal digits you should use:
integer, parameter :: Int10Type = selected_int_kind (10)
integer (kind=Int10Type) :: i
Then write your program as:
integer, parameter :: Int10Type = selected_int_kind (10)
INTEGER (Int10Type), PARAMETER :: limite = 1000000000_Int10Type, lim = 200
INTEGER (Int10Type):: i, j
DO i = 1, limite
DO j = 1, lim
!I work with a matrix
END DO
END DO
Notice that the type has also been specified on the large constant value.
Alternatively, if your compiler provides the ISO Fortran Environment feature of Fortran 2003, you can request an 8 byte (64 bit) integer in a portable way:
use iso_fortran_env
INTEGER (INT64), PARAMETER :: limite = 1000000000_INT64, lim = 200
INTEGER (INT64):: i, j
DO i = 1, limite
DO j = 1, lim
!I work with a matrix
END DO
END DO
P.S. 1000000000 should fit into a 4-byte (signed) integer since 2**31 = 2,147,483,648, so the default integer of most Fortran compilers should work. You can probably just use integer without specifying a kind! With iso_fortran_env, INT32 should suffice. If this doesn't solve your problem, perhaps your array is too big ... you may need to show us more code.
P.P.S. In response to the additional source code. The t do loop goes from 1 to total_time, but you use the 2nd index as t+1, which means that the largest value will be total_time+1. This exceeds the 2nd dimension of current. You have an array subscripting error. If you compile with subscript bounds checking the compiler will find this for you. With gfortran, either use -fcheck=all or -fbounds-check.