Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29257 Discussions

Single precision assignment to double precision

sarabjyot
Beginner
2,426 Views
I have a code in which a real*4 number is being assigned to a real*8 number i.e.
real*4 :: a
real*8 :: b
say a is some number 0.225 from calculation and when I assign it to b some additional digits are being assigned beyond 0.225. So b looks like
b = 0.225432344...etc. This is just an example. I just wish to assign a to b such that b is always accepting
0.225.
What is the right way to do it or any workaround if it cannot be done.

Thanks
0 Kudos
8 Replies
TimP
Honored Contributor III
2,426 Views
You want to round the double value to the closest multiple of 0.001d0? You must write that out explicitly. e.g.

b = anint(a*1000d0)/1000
0 Kudos
sarabjyot
Beginner
2,426 Views
Quoting - tim18
You want to round the double value to the closest multiple of 0.001d0? You must write that out explicitly. e.g.

b = anint(a*1000d0)/1000

This would only imply rouding off to the third decimal place. What I am looking for is a general way to feed a number 'a'
which is in single precision to a number 'b' in double precision without adding the extra digits.

For example what I have done is, I have a huge list of real*4 numbers which I write to a file and then read them into
a double precision array. But this process is time consuming. Instead I am looking for this to be done by means of the fortran code and without any intermediate steps of file writing.

The method you have mentioned works fine, but then I have to figure out the rounding step each time.
0 Kudos
lklawrie
Beginner
2,426 Views

There are compiler switches that "extend single precision".

Also, you could try a=real(b,kind=1.0d0)

Linda
0 Kudos
Steven_L_Intel1
Employee
2,426 Views
Quoting - lklawrie

There are compiler switches that "extend single precision".

Please do not use such switches! Instead, use the D0 suffix to mean double precision, or the "modern" way, a kind specifier. Most people do something like this:

INTEGER, PARAMETER :: DP = SELECTED_REAL_KIND(15)

to get the kind value for a REAL kind that has at least 15 decimal digits of precision. Then you can write your constants like this:

3.1415926535897_DP
0 Kudos
sarabjyot
Beginner
2,426 Views

Please do not use such switches! Instead, use the D0 suffix to mean double precision, or the "modern" way, a kind specifier. Most people do something like this:

INTEGER, PARAMETER :: DP = SELECTED_REAL_KIND(15)

to get the kind value for a REAL kind that has at least 15 decimal digits of precision. Then you can write your constants like this:

3.1415926535897_DP

Steve,

I still haven't found a way to assign a single precision to double precision variable without the additional digits. Can you please help in conversion of a real*4 array to real*8 array without the additional trailing digits that a double precision number can carry.

Thanks
0 Kudos
Steven_L_Intel1
Employee
2,426 Views
You can't - those "additional digits" are already there due to single precsion not being able to precisely represent the value with the extra decimal zeros you desire. When you extend the precision from single to double, you're adding 32 binary bits of zero to the binary fraction. The decimal number is long since forgotten.

I suggest you read the three articles The Perils of Real Numbers by Dave Eklund in the Newsletter thread. You will find them enlightening.
0 Kudos
Brian_Francis
Beginner
2,426 Views

Steve,

I still haven't found a way to assign a single precision to double precision variable without the additional digits. Can you please help in conversion of a real*4 array to real*8 array without the additional trailing digits that a double precision number can carry.

Thanks

Hi Sara,

Here is a very simple function that will return the double precision equivalent of a real, truncating the precision to 7 decimal digits.

[cpp]      real*8 function d
      real*4 r
      real*8 m
      if (r.eq.0.e0) then
        d=0.d0
      else
        m=10.d0**int(7-log10(abs))
        d=dnint(r*m)/m
      endif
      end[/cpp]
The 7-log10 bit is used to compute a multiplier that will convert the input real to a whole number with 7 digits to the left of the decimal. the dnint(r*m)/m does the work of rounding off the insignificant decimal digits and resetting the exponent.

Brian.
0 Kudos
Peter
Beginner
2,426 Views


It looks like you want to use lot of real*8 numbers but want to keep the format three digits after the decimal. right?
see if the above code works for you. You can read and write numbers as you wish by specifying the format. For example 'f6.3' would read6 digit number with3 decimal places.

Take a look at this simple code (free format)
[cpp]program main
real*8 a,b,c,d,e,f
data a,b,c,d,e,f/1.225,2.225,4.225,5.225,6.225,7.225/
open(225,file='out.txt',status='unknown')
write(225,10) a,b,c,d,e,f
10 format(f6.3)
rewind(unit=225)
read(225,10) u,v,w,x,y,z
print*, u,v,w,x,y,z
end program[/cpp]


hope it helps
0 Kudos
Reply