1

I am using the following code to calculate cos for pi/2 in Fortran.

program precision_Fortran
  IMPLICIT  NONE
  !!integer, parameter :: dp = kind(1.0d0) !!Gives same result as line below
  integer, parameter :: dp = selected_real_kind(15, 307)
  
  Real(dp), parameter:: pi=4.0*atan(1.0)
  Real(dp) :: angle

  angle = cos(pi/2.0)
  
  write(*,*)'pi = ', pi
  write(*,*)'angle = ', angle
     
end program precision_Fortran

I compiled using gfortran and ftn95. From both, the output is

 pi =    3.1415927410125732
 angle =   -4.3711390001862412E-008

How do I get a better precision for angle here? For instance in C++ I see it in order of E-18, for all declaration using double.

Please let me know if more information is needed to explain it better.

Extra : The main code I am using, with physical equations having trigonometric terms, is having precision issues, and am not entirely sure, but am suspecting it's because of this. So, want to check if above could be improved somehow. Not expert with Fortran so struggling to figure this out.

Rob
  • 3,315
  • 1
  • 24
  • 35
ZeroTwo
  • 307
  • 1
  • 3
  • 12
  • 1
    In `pi=4.0*atan(1.0)` everything on the right-hand side is in default real, so won't be as precise as if done in double precision. – francescalus Aug 26 '21 at 17:14
  • I replaced `pi` and `angle` as `pi = 4.0*atan(1.0_dp)` and `angle = cos(pi/2.0_dp)` and now it gives me in order of `E-17`. That's perfect, thanks a lot! I should delete question? – ZeroTwo Aug 26 '21 at 17:18
  • 1
    You don't need `cos(pi/2.0_dp)` instead of `cos(pi/2)` because `pi` is double precision so the `2` will be converted to double precision as part of the calculation. It doesn't hurt, though. – francescalus Aug 26 '21 at 17:24
  • 2
    There's certainly no need to delete this question, and it's your choice. Beware, however, that this question does get asked _a lot_, so there may be some risk of downvotes. – francescalus Aug 26 '21 at 17:24
  • 1
    Thanks for clearing it up... I did just try without _dp in cos, and it works fine. I quickly changed pi in my main code, and it works now! I have been on this for weeks, did go through many of those repeated posts, but missed this important point to put _dp inside argument for tan. I will keep the question undeleted, might still help someone, if they miss it like me from earlier posts. Thank you so much for all your input. – ZeroTwo Aug 26 '21 at 17:33
  • 1
    @ZeroTwo, use ```Real(dp), parameter:: pi=4.0d0*atan(1.0d0)``` – Fausto Arinos Barbuto Aug 30 '21 at 02:10
  • Thanks! I started using `Real(dp), parameter:: pi=4.0*datan(1.0d0)` Isn't that enough? I am curious if Fortran would read 4.0 as a dp by itself, or not..?? (Using datan makes it easier to figure out any error, as it gives an error if argument isn't dp...) – ZeroTwo Aug 31 '21 at 07:02
  • @francescalus I see [here in your answer](https://stackoverflow.com/a/48459164/5349262) that you recommend against using datan. What would be the reason? I realized if I use it, it's safe in the sense that if my argument is not dp, it would give me an error, so I won't miss it. – ZeroTwo Aug 31 '21 at 11:47
  • 1
    `ATAN` (standard) specific functions take only default real or double precision real arguments. Want to use with another kind real? Have to use generic anyway. Also the general advantage of generics: `real(kind=rk) x, y; x=1; y=datan(x)`. To change kind of `x` you now not only have to change `rk`'s value but also any specific which using `x`. Much simpler to change code in one place and have things work. While `datan(1.)` will give an error, there's no obvious reason why you'd want that to be an error. – francescalus Aug 31 '21 at 12:02
  • 1
    `4.0` in source code (as a literal constant) is [_never_ double precision](https://stackoverflow.com/q/33319357/3157076) (ignoring compiler flags which complicate matters). A default real such as `4.0` is _never_ "promoted" to double precision as part of procedure reference. – francescalus Aug 31 '21 at 12:22
  • All variables I use are going to be `dp` now, and if I use `datan` - all those variables as argument should fit right in. And some places, like calculation of `pi` - literal constant goes as argument. Isn't it better to keep `datan` if I need high precision so I would have that error to let me see if somewhere variable is declared with some other precision, and/or if literal constant doesn't have `_dp` with it...?? I want `datan(1.)` to give me error because when it accepted it, all my calculations (e.g. `cos(pi/2)`) were not precise up to higher order, and my results were incorrect. – ZeroTwo Aug 31 '21 at 19:52

0 Answers0