- #1

- 4

- 0

As a part of my computational physics course i have been assigned a homework which is pretty simple. My problem is in optimising my source code. So the task is this:

Write programs that calculate the machine round-off error for a real type variable with precision levels : kind=4, kind=8, kind=10. If we think this in terms of making different source codes or even a main program that will call three separate subroutines each one setting our desired amount of precision it would be easy and the code is something along the lines of this

Code:

```
PROGRAM Machine Epsilon
implicit none
integer :: exit,choice,counter
common /counts/counter ! if i declared this inside the subprogram each time it would run anew it
! would not reset the counter value. Outside seems to work just fine.
Print*,
Print*,' This program calculates the machine Round-off error,epsilon, for single, '
Print*,' double and high precision. Please specify the desired level of precision.'
Write(*,*)
5 Print*,' For single precision press 1 '
Print*,' For double precision press 2 '
Print*,' For high precision press 3 '
Print*,
Print*,' To exit press 5'
Read*, choice
do while ((choice.ne.1).and.(choice.ne.2).and.(choice.ne.3).and.(choice.ne.5))
Print*,' Invalid choice '
Print*,' Please select the amount of precision you prefer '
Print*,' for the calculation '
Print*,' For single precision press 1 '
Print*,' For double precision press 2 '
Print*,' For high precision press 3 '
Read(*,*) choice
end do
select case (choice)
case(1)
counter=0
call precision_4
case(2)
counter=0
call precision_8
case(3)
counter=0
call precision_10
case(5)
go to 60
end select
48 Print*,'Press 5 to exit or 4 to start again'
Read(*,*) exit
if ( exit .EQ. 5 ) then
go to 60
elseif ( exit .EQ. 4) then
go to 5
else
go to 48
end if
60 end program machine epsilon
c Single Precision Subroutine
c=======================================================================================================
subroutine precision_4
real(kind=4) :: temp,epsilon
integer :: counter
common /counts/counter
temp=1.5 ! the value of variable temp has been selected at random, with the sole limitation
! it being reasonably higher to the machine roundoff error for the following calculation
! to have meaning.
do while ( temp+1.0 .gt. 1.0 )
temp=temp/2.
epsilon=temp
counter=counter+1
end do
Print*,' Machine round-off error is, e = ',epsilon
Print*,' Calculated after ',counter,' repetitions'
return
end subroutine precision_4
c Double Precision subroutine
c=======================================================================================================
subroutine precision_8
real(kind=8) :: temp,epsilon
integer counter
common /counts/counter
temp=0.5
do while ( temp+1.0 .gt. 1.0 )
temp=temp/2.
epsilon=temp
counter=counter+1
end do
Print*,' Machine round-off error is, e = ',epsilon
Print*,' Calculated after ',counter,' repetitions'
return
end subroutine precision_8
c High Precision Subroutine
c=======================================================================================================
subroutine precision_10
real(kind=10) :: temp,epsilon
integer :: counter
common /counts/counter
temp=1.5 ! the value of variable temp has been selected at random, with the sole limitation
! it being reasonably higher to the machine roundoff error for the following calculation
! to have meaning.
do while ( temp+1.0 .gt. 1.0 )
temp=temp/2.
epsilon=temp
counter=counter+1
end do
Print*,' Machine round-off error is, e = ',epsilon
Print*,' Calculated after ',counter,' repetitions'
return
end subroutine precision_10
c=======================================================================================================
```

As i said, i want to optimise my program, in this sense :

I want to have only one kind of subroutine that will be calculating each time the round-off error but i want to be able to change the kind of the real type variables accordingly depending of the level of precision i want. For this reason i have tried to write something like this :

Code:

```
module PrecisionLevel
integer, parameter :: kd4=4,kd8=8,kd10=10
external epsilon
end module PrecisionLevel
PROGRAM Machine roundoff error
implicit none
integer :: ext,choice
Print*,
Print*,' This program calculates the machine Round-off error,epsilon, for single, '
Print*,' double and high precision. Please specify the desired level of precision.'
Write(*,*)
5 Print*,' For single precision press 1 '
Print*,' For double precision press 2 '
Print*,' For high precision press 3 '
Print*,
Print*,' To exit press 5'
Read*, choice
do while ((choice.ne.1).and.(choice.ne.2).and.(choice.ne.3).and.(choice.ne.5))
Print*,' Invalid choice '
Print*,' Please select the amount of precision you prefer '
Print*,' for the calculation '
Print*,' For single precision press 1 '
Print*,' For double precision press 2 '
Print*,' For high precision press 3 '
Read(*,*) choice
end do
select case (choice)
case(1)
call precision_calc(choice)
case(2)
call precision_calc(choice)
case(3)
call precision_calc(choice)
case(5)
go to 60
end select
48 Print*,'Press 5 to exit or 4 to start again'
Read(*,*) ext
if ( ext .EQ. 5 ) then
goto 60
else if ( ext .EQ. 4) then
goto 5
else
goto 48
end if
60 end program machine roundoff error
! Single Precision Subroutine
!=======================================================================================================
subroutine precision_calc(choice)
integer :: counter,choice
select case (choice)
case(1)
use PrecisionLevel, only: kd4=>kd
case(2)
use PrecisionLevel, only: kd8=>kd
case(3)
use PrecisionLevel, only:kd10=>kd
end select
real(kind=kd) :: temp,U
temp=0.5
counter=0
do while ( temp+1._kd .gt. 1._kd )
temp=temp/2._kd
U=temp
counter=counter+1
end do
Print*,' Machine round-off error is, e = ',U
Print*,' Calculated after ',counter,' repetitions'
return
end subroutine precision_calc
```

Also, does any1 know how can i see Fortran 77 / 90/95 intrinsic functions source codes? I have a hunch that be studying the structure of the mathematical intrinsic functions I can probably find a solution to my problem.

My interest is mainly academic in nature.

Thanks in advance !