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

Need function to round a double to 12 significant figures

Andrew_Smith
Geschätzter Beitragender I
1.029Aufrufe
I searched for rounding code but found all (and my own first attempt) suffered from integer overflow when using 12 significant figures. My new code makes use of a variable format internal write. The Fortran runtime appears to have a suitable rounding capability used for the IO but is it exposed to the user via any extension?

[bash]pure doubleprecision function roundNominal(num, n) result(res)
   doubleprecision, intent(in) :: num
   integer, intent(in) :: n
   character*25 temp
   if (isNaN(num)) then
      res = num
      return
   end if
   if (num == 0.0) then
      res = 0.0
      return
   end if
   write(temp, 10) num
   read(temp, *) res
10 format(0p, d25.)
end function
[/bash]
0 Kudos
5 Antworten
mecej4
Geehrter Beitragender III
1.029Aufrufe
Please elaborate on why you want to do the rounding. Is it only for decimal conversion in conjunction with I/O, or is it to examine the effect of rounding on remaining calculations?

Will truncation do, instead? Will truncation of, say, 12 bits of the signifand do? If so, here is an example. It uses the deprecated EQUIVALENCE statement, but you can rewrite it with TRANSFER.

[fortran]program chop12x

real*8 x,y
integer*4 ix(2),iy(2)
equivalence (ix,x),(iy,y)

x=acos(0d0)*2d0
y=x
call chop12(y)
write(*,'(1x,F20.16,4x,2Z8)')x,ix(2),ix(1),y,iy(2),iy(1)

contains

subroutine chop12(x)
  real*8 x,r8
  integer*4 i4(2)
  equivalence(r8,i4)

  r8=x
  i4(1)=iand(i4(1),Z'FFFFF000')
  x=r8
return
end subroutine chop12

end program chop12x
[/fortran]
The result of running this program:

[bash]   3.1415926535897930    400921FB54442D18
   3.1415926535883050    400921FB54442000
[/bash]

jimdempseyatthecove
Geehrter Beitragender III
1.029Aufrufe

Consider:

[fortran]pure doubleprecision function roundNominal(num, n) result(res)
   doubleprecision, intent(in) :: num
   integer, intent(in) :: n
   character*25 temp
   if (isNaN(num)) then
      res = num
      return
   end if
   if (num == 0.0) then
      res = 0.0
      return
   end if
   if(n == 0) then
      res = num
   end if
   if(n .gt. 0) then
      res = DNINT(num*DBLE(n)) / DBLE(n)
   else
      res = DNINT(num/DBLE(-n)) * DBLE(-n)
   endif
end function[/fortran]



Jim Dempsey

Andrew_Smith
Geschätzter Beitragender I
1.028Aufrufe
Thankyou both. DNINT will obviously do what I want. I should have searched a bit more before posting this.
jimdempseyatthecove
Geehrter Beitragender III
1.029Aufrufe
Also note that temp should be removed, and you should use double precision literals for 0.0 (0.0D0)

Jim Dempsey

Steven_L_Intel1
Mitarbeiter
1.028Aufrufe
Please use the generic ANINT rather than the specific DNINT. In general, I recommend against using specific functions unless you are passing them as actual arguments.
Antworten