Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Call the same subroutine/function with different precision

  1. Oct 24, 2011 #1
    Hello everyone,

    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 (Text):
          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 (Text):

          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
    The idea is to incert a module which will set the kind in an integer-parameter and it will be used later on depending on the selection of the user. Since it is the first time i have ever needed to write something like that could you please tell me if the syntax i am using is even possible ? My idea is that each time the subroutine precison_calc(choice) will be called a different type of use command will be activated depending on the original choice of the user. But can i use the "use" statement in such a way either inside or outside the subroutine?

    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 !
     
  2. jcsd
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook

Can you offer guidance or do you also need help?
Draft saved Draft deleted



Similar Discussions: Call the same subroutine/function with different precision
Loading...