Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Fortran 95 kind conversion

Status
Not open for further replies.

semmmmml

Technical User
Jan 26, 2015
6
AT
Hello,
I want to convert an integer variable into a selected_real_kind but I am not sure how to do this. Can anyone help me? The code looks like this:

integer, parameter :: rk = selected_real_kind(15,307) !in this case double precision
integer :: a = 10
real(rk) :: b

b = 1._rk/a !here I get zero (integer division)
b = 1._rk/10._rk !here I get 0.1
b = 1._rk/(a)_rk !here I get a compiler error (gfortran)

My question is: what is the equivalent to dble(a) for a general kind conversion?
 
Hhhhmmm...I have read about these new precision styles, but refuse to use them...I just find rather convoluted and I don't think I have need for it, so far...oh well.

In any case...

I don't think integer variable a is causing the zero, for as long as the numerator is not integer, a should be promoted.

Try explicit "real(kind=rk)"

Just in case, make sure that your request for rk is being honored, i.e., it is working...if rk is -1, -2 or -3 is not working.

You may want to post a minimal, non-working source for us to take a better look...it could very well be something else in your program that is causing the behavior that you don't like.
 
You are right, the integer has to be in the numerator, but my question is still the same.
This is a minimal example:

Code:
program conversion
  implicit none

  integer, parameter :: rk = selected_real_kind(15,307)
  integer :: a = 10, b = 5
  real(rk) :: c

!integer division but integer output -> works
  c = a/b
  write (*,*) c
!integer division but non integer output -> zero
  c = b/a
  write (*,*) c
!works, but I guess I might lose precision or get a kind mismatch in more complex situations when I set rk to higher precision
  c = dble(b)/a
  write (*,*) c
!this trick seems to work, but I am not too fond of it
  c = 1._rk*b/a
  write (*,*) c

end program conversion

This code is working, but what I am looking for is a nicer way to write c = 1._rk*b/a, something like c = (b)_rk/a which unfortunately produces a compiler error.
 
semmmmml:

Regarding your 4 cases above:
1) it is working, with an integer as immediate result of integral division but promoted upon assignment to real(rk) c variable.
2) it is working, with an integer as immediate result of integral division but promoted upon assignment to real(rk) c variable. Just because the result is zero it does not mean is not working or that it is not integer...0 is the correct answer for integral division of a value divided by a greater one.
3) this works and it is one correct way to avoid integral division when one would otherwise happen due to type of operands.
4) this happens to work but only because the operators have the same priority and, thus, operations executed from left to right; option (3) is better and is clearer regarding awareness and intent.

And, no, you are not loosing precision in any of these cases...you are just not magically gaining any either. When you assign a double precision value to a single precision variable, you loose precision. When you assign a lower precision value to a higher precision variable, you can't magically gain precision and expect the far away decimals to be set correctly...they may be noise...it is only when you truly carry operations with all higher precision values that you can count on all decimals being correctly set.

So, be mindful and try to understand better what you are doing and what all this means.
 
Hello salgerman,

thank you for your explanation. I understand all the above and of course I understand that I do not gain precision by converting an integer into a real. Actually I just wanted to know, if there was an easy way to convert an integer into a selected_real_kind. This is why i did not put much effort in finding an example where you see the loss of precision. (In the above example you can't see it because real(rk) is the same as real(8).

Let me give you a better example:

Code:
program conversion
  implicit none

  integer, parameter :: rk = selected_real_kind(17,307)
  real(rk) :: pi = 3.14159265358979323846264338327950288419716939937510582
  integer :: a = 10, b = 1
  real(rk) :: c

! comparison of dble and rk
  write(*,*) pi
  write(*,*) dble(pi)

!adding 0.1 to pi/10
  c = 0.1_rk + pi/dble(a)
  write(*,*) c

!loss of precision
  c = dble(b)/dble(a) + pi/dble(a)
  write(*,*) c

!step by step to analyse where we made the mistake
  c = dble(b)/dble(a)
  write(*,*) c
  c = c + pi/dble(a)
  write(*,*) c

end program conversion

Here I lose precision! The digits that exceed the number of digits of double precision seem to be random. I am not sure how to solve this problem, nor if this is compiler dependent. I use gfortran.
 
Again...there is no loss of precision on anything that you are showing above. Please explain more clearly with text output and the like, where exactly you see loss of precision.

First of all, you are fooling yourself by assigning to PI a number with that many decimal places...they are being lost right away as your have selected a kind that only guarantees 17 decimal places, in the first place: "selected_real_kind(17,307). Is this clear?

Second, you need to be aware that YOU like working on base 10, yet, you are working on a computer that stores numbers in base 2 !!!...Not every decimal number can be represented in binary and, so, you will notice that a hard coded number that you enter may end up being a slightly different number as soon as it is stored in the computer.

Here is a print out of what I am getting from your program after explicitly specifying output format f30.25 to show that things remain consistent up to 17 significant digits and after that (the blank space) anything goes.

Code:
 rk =           10
pi         =    3.1415927410125732 421875000
dble(pi)   =    3.1415927410125732 421875000
0.1+pi/a,c =    0.41415927410125732 42133300
b/a+pi/a,c =    0.41415927410125732 97698700
c=b/a,   c =    0.10000000000000000 55511200
c+=pi/a  c =    0.41415927410125732 97698700

 
Yes, I am aware that many of the digits get lost right away, I just copied them in and was too lazy to delete the obsolete ones. And about the output: my mistake! Again, I didn't count the digits and didn't think that write(*,*) prints irrelevant digits. My output looks like this:

Code:
3.14159274101257324219
3.1415927410125732
0.414159274101257324213
0.414159274101257329770
0.100000000000000005551
0.414159274101257329770

As the second output is cut off a few digits earlier and the second last gets random digits there, I assumed this is where I lose information. But, of course, you are right! Up to the 17th digit everything is okay.

BUT... now another things stumbles me: my input for pi is
3.141592 65358979323846​
and my output (as well as yours) right away is
3.141592 74101257324219​

SEEMS LIKE INFORMATION WAS LOST AT THE 7TH DIGIT HERE ????
I'm confused...
 
That I am not 100% sure; but, like I said, this most probably has something to do with decimal vs binary representation.
 
After doing some digging, I came to the following result:
The cut off after the 7th digit came from not initializing pi correctly
wrong:
real(rk) :: pi = 3.14159265358979323846264338327950288419716939937510582​
correct:
real(rk) :: pi = 3.14159265358979323846264338327950288419716939937510582_rk​

The first line gives me a real(rk) variable with precision of a real(4)!

Now let's have a look at the program again:

Code:
program conversion
  implicit none

  integer, parameter :: rk = selected_real_kind(21,307)
  real(rk) :: pi = 3.14159265358979323846264338327950288419716939937510582_rk
  integer :: a = 10, b = 1
  real(rk) :: c

! comparison of dble and rk
  write(*,*) pi
  write(*,*) dble(pi)

!adding 0.1 to pi/10
  c = 0.1_rk + pi/dble(a)
  write(*,*) c

!loss of precision
  c = dble(b)/dble(a) + pi/dble(a)
  write(*,*) c

end program conversion

and the result:

Code:
!here I get a minimum of 21 decimals although I gain a few because the bits for the exponent are free
   3.14159265358979323846 264338327950280
!here I get a minimum of 15 decimals and gain one decimal because no exponent
   3.14159265358979 31
!the region between the two spaces is the range from 15 to 21 decimals, where I clearly lose precision
  0.414159265358979 323846 264338327950318
  0.414159265358979 329397 379461453732991

So, I'm sorry, but I have to revoke the statement of my last post. It just looked like we are not losing precision because we lost it right in the beginning and because, in case we don't have an exponent, it is hard to tell exactly how many decimals of precision we will get. 15 and 21 in this case is just the lower limit and those two values seem to be far enough apart to observe the loss of precision.

Thus my question seems to be justified and remains the same:
IS THERE A WAY TO CONVERT AN INTEGER INTO A GENERAL REAL KIND?
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top