2

I'm testing out ranges of values (-1:34 just for kicks) for the function selected_real_kind to determine the kind parameter it returns and the actual number of bits of precision used by a variable defined using this kind. I'm stuck with how to define variable RP below, though, since the function to convert the variables x, u and alpha (real(x,RP) e.g.) require that RP (the kind type) to be constant.

If I define RP to be a parameter, i.e. at the top write integer, parameter :: RP I have to initialize it immediately, and then I obviously can't change it because, well, it's a parameter, so this won't work.

Here's what I have:

program f1
  implicit none
  integer :: n,t  ! n used in selected_real_kind(n), t is precision (#bits)
  integer :: RP
  real :: x=1.5, u=1.0, alpha=1.0  ! will be reset using _RP below                                                                               

  print '(A2,A4,A4)', "n", "RP", "t"  ! header for values

  do n=-1,34
     RP = selected_real_kind(n)

     ! convert x,u,alpha to type RP.  These functions throw the error!                               
     x = real(x,RP)
     u = real(u,RP)
     alpha = real(alpha,RP)

     ! init precision test variables                                                                                                             
     x=1.5_RP
     u=1.0_RP
     alpha=1.0_RP

     ! reset precision value to zero before each test                                                                                            
     t = 0

     ! precision test                                                                                                                            
     do while(x>alpha)
        u = u/2.0_RP
        x = alpha+u
        t = t+1
     end do

     print '(I2 I4 I4)', n, RP, t
  end do

end program f1
bcf
  • 2,104
  • 1
  • 24
  • 43
  • 1
    You have an answer explaining that this approach is tricky. However, I will say that having `x=real(x,RP)` and `x=1.5_RP` (with `RP` an appropriate constant expression (first case) and named constant (second case)) still doesn't make `x` anything other than a default real. – francescalus Aug 27 '14 at 19:18
  • See also: http://stackoverflow.com/q/9569756/3157076. This isn't exactly the same, but addresses the "I want to have a varying constant expression" point. – francescalus Aug 27 '14 at 19:20
  • @francescalus Could you elaborate as to why these don't properly convert `x` to a real with kind parameter `RP`? I've read "REAL(A, KIND) is converted to a real type with kind type parameter KIND if A is a complex, integer, or real variable." from the documentation. – bcf Aug 27 '14 at 19:44
  • 1
    its not clear what you are really trying to do, but consider writing a wrapper program that generates the source for a specific `n`, compiles and runs it, then loop that. – agentp Aug 27 '14 at 19:53
  • The _result_ of `real(a,kind)` is of kind `kind`. However, the result is assigned to `x` which is of its declared kind, by a process defined as `real(real(a,kind))`. (Except for polymorphic `x`) `x` is always of its declared kind. – francescalus Aug 27 '14 at 19:55
  • @george I thought of that as well, do you mean writing a bash script that feeds `n` into this program in a loop? For this I tried to find the Fortran equivalent of `argc **argv` in `C++`, but couldn't find anything – bcf Aug 27 '14 at 20:14

3 Answers3

1

Fortran provides a number of intrinsic functions for enquiring into the characteristics of the numbers it processes. Consult your documentation for functions such as digits, precision and radix. All of these (including the ones I haven't mentioned but which your documentation will list) are generic (enough) to work on inputs of all the numeric kinds supported by your compiler.

You'll make headway faster using these functions than trying to roll your own. As you are discovering it's not a simple matter to write your own generic routines as Fortran wants kind selectors known (or knowable) at compile time. You'll also extend your knowledge of Fortran.

You may also find functions of interest in the intrinsic module IEEE_ARITHMETIC.

High Performance Mark
  • 77,191
  • 7
  • 105
  • 161
1

elaborating on my comment, here is a python example:

 fortrancode = """
       implicit none
       integer, parameter :: n=%i
       integer,parameter :: rp=selected_real_kind(n)      
       write(*,*)n,rp
       end
 """
 from subprocess import call
 for n in range(-1,33):
  f=open('test.f','w')
  f.write(fortrancode%(n))  ! <- n here gets string substituted
                            !for the '%i' in fortrancode
  f.close()
   ! optional check  call(['grep','n=','test.f'])
  call(['gfortran','test.f','-o','test.exe'])
  call(['./test.exe'])

python test.py

 -1 4
  0 4
  1 4
...
  7 8
...
 18 10
 19 -1
...
 32 -1
agentp
  • 6,849
  • 2
  • 19
  • 37
1

Similar to george's answer, but in Fortran. We note that kinds are something that, essentially, must be known at compile-time. For that we ask the compiler which kinds it can offer us and, for each of those, create a small chunk of code to be compiled. Then compile and run it. [This last step certainly varies by system.]

! Rather than looping over a range with SELECTED_REAL_KIND, just see which
! real kinds are available to the compiler.  We can later match up real kinds
! for a requested precision with those here.
  use, intrinsic :: iso_fortran_env, only : real_kinds
  implicit none

  integer output
  integer i

  open(newunit=output, file='gosh.f90', action='write', position='rewind')

! Here we could instead do n=-1, 34 etc.
  do i=1, SIZE(real_kinds)
     write(output, 1) real_kinds(i)
  end do

  write(output, '("end")')
  close(output)

! A compile/execute line - do whatever is required.
  call execute_command_line('compile gosh.f90 && ./a.out')

1 FORMAT ("block",/,"real(",I0,") x",/,"include 'domystuffz'"/,"end block")

end

where "domystuffz" is a file containing whatever analysis is wanted. As with High Performance Mark's answer something intrinsic would be nice and the include could be replaced by some simple code if required.

Community
  • 1
  • 1
francescalus
  • 30,576
  • 16
  • 61
  • 96