• DCOS error

    From ritchie31@21:1/5 to All on Sat Mar 19 16:18:27 2022
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))

    but I got:

    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision

    Any help is appreciated.
    Regards

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to All on Sat Mar 19 18:51:06 2022
    On Sunday, March 20, 2022 at 10:18:29 AM UTC+11, ritchie31 wrote:
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))

    but I got:

    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision

    Any help is appreciated.

    It's telling you what is wrong. The argument is not double precision.
    Your argument is single precision.

    As well as that, you have mis-spelled "float" as "fioat".

    The kind of ZI is irrelevant.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From ritchie31@21:1/5 to Robin Vowels on Sat Mar 19 20:11:49 2022
    On Saturday, March 19, 2022 at 8:51:09 PM UTC-5, Robin Vowels wrote:
    On Sunday, March 20, 2022 at 10:18:29 AM UTC+11, ritchie31 wrote:
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))

    but I got:

    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision

    Any help is appreciated.
    It's telling you what is wrong. The argument is not double precision.
    Your argument is single precision.

    As well as that, you have mis-spelled "float" as "fioat".

    The kind of ZI is irrelevant.
    Thank you for your answer.Sorry, that "I" in FLOAT was lower case L. I did change that.
    How can I change my declaration to Double precision?
    Do I have to do something different with the integer I?
    Regards

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From ritchie31@21:1/5 to All on Sat Mar 19 20:12:06 2022
    On Saturday, March 19, 2022 at 10:05:21 PM UTC-5, gah4 wrote:
    On Saturday, March 19, 2022 at 4:18:29 PM UTC-7, ritchie31 wrote:
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))
    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision
    The traditional solution is to use DFLOAT instead of FLOAT.
    It is not accepting that.
    I use gfortran.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to All on Sat Mar 19 20:05:19 2022
    On Saturday, March 19, 2022 at 4:18:29 PM UTC-7, ritchie31 wrote:
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))

    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision

    The traditional solution is to use DFLOAT instead of FLOAT.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From ritchie31@21:1/5 to All on Sun Mar 20 00:51:20 2022
    On Saturday, March 19, 2022 at 10:26:28 PM UTC-5, gah4 wrote:
    On Saturday, March 19, 2022 at 8:12:09 PM UTC-7, ritchie31 wrote:

    (snip, I wrote)
    The traditional solution is to use DFLOAT instead of FLOAT.

    It is not accepting that.
    I use gfortran.
    In that case, the next to traditional solution is DBLE(FLOAT(I))
    (And both of those are in the newest standard, so that should work.)

    The more modern solution is REAL(I, KIND(1.D0))
    Thank you very much!
    DBLE worked!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Van Buskirk@21:1/5 to All on Sun Mar 20 02:39:45 2022
    "ritchie31" wrote in message news:4d303cee-275c-4f8a-a75f-854a8fc21498n@googlegroups.com...

    On Saturday, March 19, 2022 at 10:26:28 PM UTC-5, gah4 wrote:

    On Saturday, March 19, 2022 at 8:12:09 PM UTC-7, ritchie31 wrote:

    (snip, I wrote)
    The traditional solution is to use DFLOAT instead of FLOAT.

    It is not accepting that.
    I use gfortran.
    In that case, the next to traditional solution is DBLE(FLOAT(I))
    (And both of those are in the newest standard, so that should work.)

    The more modern solution is REAL(I, KIND(1.D0))
    Thank you very much!
    DBLE worked!

    But it's the wrong solution because the inputs aren't double precision. Instead, I propose that you add the declaration

    DOUBLE PRECISION, PARAMETER:: PI = 4*ATAN(1.0D0)

    Then you could use this double precision realization of pi later as

    ZI = DCOS((2*( I - 1) + 1)*PI/(2*M))

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to medina.rc@gmail.com on Sun Mar 20 08:54:23 2022
    ritchie31 <medina.rc@gmail.com> schrieb:
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))

    There are a few issues with that line.

    It is generally not a good idea to use the specific intrinsic
    functions. You can use the generic COS instead, which takes the
    type of its argument (which has to be real, of course). This was
    introduced in Fortran 77, your code may be older.

    If you want to do use double precision, then you should use DBLE.

    The constant 3.1415927 is a single precision constant, and has
    fewer digits than would be required for double precision accurracy.
    You get no benefit from double precision when you use this formula.
    Consider

    program x
    double precision pi, a
    pi = atan(1.d0)*4
    a = 3.1415927
    print *,pi
    print *,a
    end program x

    which yields (with gfortran)

    3.1415926535897931
    3.1415927410125732

    (note that the last digit is off by one, but the number, when
    read in, gets the exact binary pattern of pi back)

    You should either put in 3.141592741012573D0 as your constant,
    or, much better, declare it as a parameter. Modern Fortran
    and modern compilers will accept

    double precision, parameter :: pi = 4*atan(1.d0)

    or, if you prefer older style

    DOUBLE PRECISION PI
    PARAMETER (PI = 3.141592741012573D0)

    or, using the new

    DOUBLE PRECISION PI
    PARAMETER (PI = 4*ATAN(1.D0))

    Several other variants and combinations are also possible
    (of course).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JCampbell@21:1/5 to James Van Buskirk on Sun Mar 20 02:00:50 2022
    On Sunday, March 20, 2022 at 7:40:08 PM UTC+11, James Van Buskirk wrote:
    "ritchie31" wrote in message
    news:4d303cee-275c-4f8a...@googlegroups.com...
    On Saturday, March 19, 2022 at 10:26:28 PM UTC-5, gah4 wrote:

    On Saturday, March 19, 2022 at 8:12:09 PM UTC-7, ritchie31 wrote:

    (snip, I wrote)
    The traditional solution is to use DFLOAT instead of FLOAT.

    It is not accepting that.
    I use gfortran.
    In that case, the next to traditional solution is DBLE(FLOAT(I))
    (And both of those are in the newest standard, so that should work.)

    The more modern solution is REAL(I, KIND(1.D0))
    Thank you very much!
    DBLE worked!
    But it's the wrong solution because the inputs aren't double precision. Instead, I propose that you add the declaration

    DOUBLE PRECISION, PARAMETER:: PI = 4*ATAN(1.0D0)

    Then you could use this double precision realization of pi later as

    ZI = DCOS((2*( I - 1) + 1)*PI/(2*M))
    I agree with using a double precision calculation of pi. That would fix the problem.
    For clarity, I would also use double precision rad ; rad = (2*( I - 1) + 1)*PI/(2*M)
    There would be no precision loss with or without FLOAT, as 2*(I-1)+1 and 2*m are the same when converted to real or double precision.
    Why use DCOS, as COS is generic ?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to JCampbell on Sun Mar 20 02:18:14 2022
    On Sunday, March 20, 2022 at 2:00:53 AM UTC-7, JCampbell wrote:

    (snip)
    I agree with using a double precision calculation of pi. That would fix the problem.
    For clarity, I would also use double precision rad ; rad = (2*( I - 1) + 1)*PI/(2*M)
    There would be no precision loss with or without FLOAT, as 2*(I-1)+1 and 2*m are the same when converted to real or double precision.
    Why use DCOS, as COS is generic ?

    If he used COS, then there would be no error, and no idea that it wasn't
    using double precision COS. Then there would be no reason to ask here.

    And, for those with Echo:

    "Alexa, what is the tangent of 90 degrees?"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to All on Sun Mar 20 03:50:56 2022
    On Sunday, March 20, 2022 at 2:11:51 PM UTC+11, ritchie31 wrote:
    On Saturday, March 19, 2022 at 8:51:09 PM UTC-5, Robin Vowels wrote:
    On Sunday, March 20, 2022 at 10:18:29 AM UTC+11, ritchie31 wrote:
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))

    but I got:

    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision

    Any help is appreciated.
    It's telling you what is wrong. The argument is not double precision.
    Your argument is single precision.

    As well as that, you have mis-spelled "float" as "fioat".

    The kind of ZI is irrelevant.
    .
    Thank you for your answer.Sorry, that "I" in FLOAT was lower case L. I did change that.
    How can I change my declaration to Double precision?
    .
    Use the keywords DOUBLE PRECISION
    .
    Do I have to do something different with the integer I?

    You need to write DBLE(I), as in 2*DBLE(I)-1
    It would be better to write 2*DBLE(M)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to JCampbell on Sun Mar 20 03:58:38 2022
    On Sunday, March 20, 2022 at 8:00:53 PM UTC+11, JCampbell wrote:
    On Sunday, March 20, 2022 at 7:40:08 PM UTC+11, James Van Buskirk wrote:
    "ritchie31" wrote in message
    news:4d303cee-275c-4f8a...@googlegroups.com...
    On Saturday, March 19, 2022 at 10:26:28 PM UTC-5, gah4 wrote:

    On Saturday, March 19, 2022 at 8:12:09 PM UTC-7, ritchie31 wrote:

    (snip, I wrote)
    The traditional solution is to use DFLOAT instead of FLOAT.

    It is not accepting that.
    I use gfortran.
    In that case, the next to traditional solution is DBLE(FLOAT(I))
    (And both of those are in the newest standard, so that should work.)

    The more modern solution is REAL(I, KIND(1.D0))
    Thank you very much!
    DBLE worked!
    But it's the wrong solution because the inputs aren't double precision. Instead, I propose that you add the declaration

    DOUBLE PRECISION, PARAMETER:: PI = 4*ATAN(1.0D0)

    Then you could use this double precision realization of pi later as

    ZI = DCOS((2*( I - 1) + 1)*PI/(2*M))
    I agree with using a double precision calculation of pi. That would fix the problem.
    For clarity, I would also use double precision rad ; rad = (2*( I - 1) + 1)*PI/(2*M)
    There would be no precision loss with or without FLOAT, as 2*(I-1)+1 and 2*m are the same when converted to real or double precision.

    No they are not. They both can overflow. Both I and M need to be converted using DBLE first.

    Why use DCOS, as COS is generic ?

    In this case, the OP would not have noticed the thee errors in the RHS.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to Thomas Koenig on Sun Mar 20 04:10:10 2022
    On Sunday, March 20, 2022 at 7:54:26 PM UTC+11, Thomas Koenig wrote:
    ritchie31 <medi...@gmail.com> schrieb:
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))
    There are a few issues with that line.

    It is generally not a good idea to use the specific intrinsic
    functions. You can use the generic COS instead, which takes the
    type of its argument (which has to be real, of course). This was
    introduced in Fortran 77, your code may be older.

    If you want to do use double precision, then you should use DBLE.

    The constant 3.1415927 is a single precision constant, and has
    fewer digits than would be required for double precision accurracy.
    You get no benefit from double precision when you use this formula.
    Consider

    program x
    double precision pi, a
    pi = atan(1.d0)*4
    a = 3.1415927
    print *,pi
    print *,a
    end program x

    which yields (with gfortran)

    3.1415926535897931
    3.1415927410125732

    (note that the last digit is off by one, but the number, when
    read in, gets the exact binary pattern of pi back)

    You should either put in 3.141592741012573D0 as your constant,

    What? That isn't the value of pi.
    If that's the value the OP wants, he can leave it as it was, viz,
    3.1415927
    But since the OP wants a double precision result for COS,
    he needs to write
    3.1415926535897931D0
    or something equivalent (viz, 4*ATAN(1.0D0) as you suggested below).

    or, much better, declare it as a parameter. Modern Fortran
    and modern compilers will accept

    double precision, parameter :: pi = 4*atan(1.d0)

    or, if you prefer older style

    DOUBLE PRECISION PI
    PARAMETER (PI = 3.141592741012573D0)

    or, using the new

    DOUBLE PRECISION PI
    PARAMETER (PI = 4*ATAN(1.D0))

    Several other variants and combinations are also possible
    (of course).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to All on Sun Mar 20 03:45:28 2022
    On Sunday, March 20, 2022 at 2:05:21 PM UTC+11, gah4 wrote:
    On Saturday, March 19, 2022 at 4:18:29 PM UTC-7, ritchie31 wrote:
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))
    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision
    The traditional solution is to use DFLOAT instead of FLOAT.
    .
    No it's not. It's DBLE.
    As well, the constant pi needs to be written as double precision.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to James Van Buskirk on Sun Mar 20 03:54:26 2022
    On Sunday, March 20, 2022 at 7:40:08 PM UTC+11, James Van Buskirk wrote:
    "ritchie31" wrote in message
    news:4d303cee-275c-4f8a...@googlegroups.com...
    On Saturday, March 19, 2022 at 10:26:28 PM UTC-5, gah4 wrote:

    On Saturday, March 19, 2022 at 8:12:09 PM UTC-7, ritchie31 wrote:

    (snip, I wrote)
    The traditional solution is to use DFLOAT instead of FLOAT.

    It is not accepting that.
    I use gfortran.
    In that case, the next to traditional solution is DBLE(FLOAT(I))
    (And both of those are in the newest standard, so that should work.)

    The more modern solution is REAL(I, KIND(1.D0))
    Thank you very much!
    DBLE worked!
    But it's the wrong solution because the inputs aren't double precision. Instead, I propose that you add the declaration

    DOUBLE PRECISION, PARAMETER:: PI = 4*ATAN(1.0D0)

    Then you could use this double precision realization of pi later as

    ZI = DCOS((2*( I - 1) + 1)*PI/(2*M))

    That's no good, because 2*M can overflow, likewise 2*(I-1)+1
    See earlier suggestion.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to All on Sun Mar 20 04:40:32 2022
    On Sunday, March 20, 2022 at 8:00:53 PM UTC+11, JCampbell wrote:
    .
    With all the wrong advice here, seems like a good reason to use PL/I.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John@21:1/5 to All on Sun Mar 20 10:45:59 2022
    so to summarize, using an arbitrary precision calculation from the
    GNU/Linux version of bc(1) and some somewhat arbitrary I and M values to
    get a few reference values:

    scale=50 pi=3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709

    i=3
    m=8
    c( (2*(i-1)+1)*pi/ (2*m) )

    i=30
    m=30
    c( (2*(i-1)+1)*pi/ (2*m) )

    i=2147483647
    m=2147483647
    c( (2*(i-1)+1)*pi/ (2*m) )

    i=2147483647/2+1000
    m=2147483647/2+1234
    c( (2*(i-1)+1)*pi/ (2*m) )
    ```
    we get

    .55557023301960222474283081394853287437493719075480 -.99862953475457387378449205843943658059095229076778 -.99999999999999999973248383642001669587197950999122 -.99999999999976462804957484993760994845013547247662

    And then compare the original with a minimal change from FLOAT to DFLOAT
    to the simplest generic syntax and a statement corrected to explicitly
    handle all type conversions to double precision we get


    program show
    ! using an appropriate kind instead of explicitly using DOUBLE PRECISION integer,parameter :: dp=kind(0.0d0)
    ! getting a more accurate representation of PI appropriate for the KIND used real(kind=dp),parameter :: PI=4*atan(1.0_dp)
    integer :: i,m
    real(kind=dp) :: zi, zi_old
    i=3
    m=8
    call printme()
    i=30
    m=30
    call printme()
    i=huge(0)
    m=huge(0)
    call printme()
    i=huge(0)/2+1000
    m=huge(0)/2+1234
    call printme()

    contains

    subroutine printme()
    ! convert integers early to prevent overflow
    write(*,*)'I=',i,'M=',m
    zi = cos( (2*real(i-1,kind=dp)+1)*PI/ (2*real(m,kind=dp)) )
    write(*,*)zi

    ! using generic and simple statement with just PI double precision write(*,*)cos( (2*(i-1)+1)*PI/ (2*m) )

    ! original except change FLOAT() to DFLOAT()
    ZI_old = DCOS(DFLOAT(2*( I - 1) + 1)*3.1415927/DFlOAT(2*M))
    write(*,*)zi_old

    end subroutine printme

    end program show


    I= 3 M= 8
    0.555570233019602
    0.555570233019602
    0.555570210304169
    I= 30 M= 30
    -0.998629534754574
    -0.998629534754574
    -0.998629539253669
    I= 2147483647 M= 2147483647
    -1.00000000000000
    -1.836970198721030E-016
    1.311341700055869E-007
    I= 1073742823 M= 1073741828
    -0.999999999995767
    -0.999999999995767
    -0.999999999996017

    compared to the "reference" values

    .55557023301960222474283081394853287437493719075480 -.99862953475457387378449205843943658059095229076778 -.99999999999999999973248383642001669587197950999122 -.99999999999976462804957484993760994845013547247662

    So a simple statement using generics (that happens to cause automatic promotion) can get good answers over a wide range of input values
    and is much more readable; but to harden the routine over the entire
    range of values for integer inputs and to not use "hidden" conversions
    it is best to not depend on automatic promotion of variables as all,
    possibly introducing new variables to make it more readable, such as

    real(kind=dp) :: ri, rm
    ri=i
    rm=m
    So the summary conclusion seems to be to avoid implicit conversion
    entirely? There are times where integers make it much more explicit
    that the compiler can optimize certain calculations, I would say.

    ! CONCENSUS ???
    program show
    ! using an appropriate kind instead of explicitly using DOUBLE PRECISION integer,parameter :: dp=kind(0.0d0)
    ! getting a more accurate representation of PI appropriate for the KIND used real(kind=dp),parameter :: PI=4*atan(1.0_dp)
    integer :: i,m
    real(kind=dp) :: zi, ri, rm
    i=3
    m=8

    ! no implicit type conversions avoids several issues, such as inadvertent
    ! integer overflow
    ri=real(i,kind=dp)
    rm=real(m,kind=dp)
    zi=cos( (2.0_dp*(ri-1.0_dp)+1.0_dp)*PI/ (2.0_dp*rm) )

    end program show

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ron Shepard@21:1/5 to All on Sun Mar 20 13:48:30 2022
    On 3/19/22 6:18 PM, ritchie31 wrote:
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))

    but I got:

    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision

    Any help is appreciated.
    Regards

    Wow, there is a lot to unpack in that statement, and many of the
    suggestions in this thread are off mark.

    First, it does not matter what is the type or kind of ZI. The expression
    on the right is evaluated as it stands regardless.

    Second, you almost certainly should not be using specific intrinsic
    functions such as DCOS, FLOAT, DFLOAT, DBLE, and so on as many have
    suggested. There are times to use those kinds of functions, when
    purposely doing mixed-precision arithmetic, but your application is
    probably not one of those.

    So how should this be written if you want to have simple and robust
    code? First, the value of PI in the expression above is single
    precision. That is, it is the default real kind. If you want extended precision, then you should either declare the constant appropriately or
    you should specify the appropriate kind of the literal constant and add
    in the missing digits. Let's do it like this, not because this is
    inherently better than other approaches, but because no one else has
    suggested this yet.

    integer, parameter :: wp = selected_real_kind(14)
    REAL(WP), PARAMETER:: PI = 4 * ATAN(1.0_wp)

    The wp parameter is appropriate for double precision on many machines,
    but that is a way to specify the minimum precision independently of what
    your compiler thinks is the default. That is more or less the modern
    standard equivalent to REAL*8. You could also declare things like

    integer, parameter :: wp = kind(1.0d0)

    to force the working precision to be what your compiler thinks is double precision. Or, you could declare it as

    integer, parameter :: wp = kind(ZI)

    where ZI has been declared elsewhere, maybe in a module, but you might
    not know what it is, you just know that you want to be consistent with
    that kind. With the appropriate kind defined, you could also specify the literal constant as, for example,

    3.1415926535897931_wp

    either in a parameter definition or in the original expression itself. I
    don't really recommend that latter option, but if you wanted to do that,
    it would at least be better than specifying the literal constant to have
    the incorrect kind.

    In any case, once PI is defined to be of the correct type and kind for
    the expression you want to evaluate, and to have the correct value for
    that kind. Then you can evaluate the expression as

    ZI = COS( (2*( I - 1) + 1) * PI / (2*M))

    The COS intrinsic is generic, so it evaluates its result to be
    consistent with whatever its argument is. What is that? Fortran has well defined rules for evaluating expressions of mixed type. In that
    expression, the (2*(I-1)+1) will be evaluated as an integer expression
    because it is enclosed in parentheses. The kind will be KIND(I), which
    is probably whatever the compiler thinks is the default integer kind. If
    the values don't get too big, that will be fine. If they get up around
    10**9 or so, then you might need to worry about integer overflow, which
    is usually silent at runtime, so you should beware of that. Similarly,
    the (2*M) part of the expression is also evaluated as an integer
    expression of KIND(M). Without further knowledge of the declarations,
    that is all that we can say about the integer factors in the expression.
    If I or M are nondefault kind, say they are 64-bit integers, then the expressions will be evaluated with the higher precision of that kind or
    the default kind. That is, either the value of I will be converted to
    the default kind, or the default kind values of 2 and 1 will be
    converted to the declared kind of I or M. The language gives you control
    over those conversions if you don't want the default behavior. The
    advantage of avoiding the specific intrinsic functions is that in the
    future if the kind values need to change, say because some compiler has different defaults, then you only need to change the wp parameter
    declaration to get the correct results, you don't need to go back into
    the code and change each occurrence in each expression of a
    kind-specific intrinsic function. If you take care and write your code
    the right way, then that wp parameter can be changed in a single place,
    and that change will propagate throughout your entire program with no
    further manual changes.

    Then an expression equivalent to

    K*PI/L

    is evaluated, where K and L are the values of those integer expressions
    of their appropriate kinds. The compiler is free to evaluate that in
    either of two ways, (K*PI)/L or as K*(PI/L). In the first case, the
    value of K is converted to a real value with the same kind as PI, the multiplication is done with that precision. Then the value of L is
    converted to real with kind(PI) and the final division is performed. The
    other option is to convert L first, then divide, then convert K, and
    then multiply the result. There usually isn't any need to specify which
    of those are chosen, so you can let the compiler decide. It might be
    able to optimize those operations a little by reusing a register value,
    or perhaps by reusing a previous conversion from a nearby statement. You
    may not get the same value for those two expressions, but they should be
    the same except possibly for the last bit or two, which is really all
    you can expect from floating point arithmetic.

    Some programmers like to specify type conversions explicitly.
    Particularly those using other languages with different implicit
    conversion semantics. In that case, then one might write the original expression as something like

    ZI = COS( REAL(2*(I-1)+1,KIND=wp) * PI / REAL(2*M,KIND=wp) )

    Others prefer the shorter version. The important point though is that
    this longer expression evaluation does not require any more effort than
    the shorter expression, it will compile to exactly the same
    instructions. It is just specifying explicitly what the compiler is
    required already to do implicitly.

    In any case, you then have the real argument evaluated without
    significant loss of precision for the COS() evaluation. COS is generic,
    so it takes whatever KIND it argument has, and evaluates the result in
    that precision. At this point, if PI has been declared incorrectly, or
    if it had been specified with the wrong kind as in the original code,
    then it would produce results with that wrong precision. But if PI has
    been declared correctly, then it will be evaluated with the correct
    precision, no less and no more.

    After COS() is evaluated, then the value is assigned to the ZI variable.
    If your declarations were consistent, then that assignment is just a
    register to memory copy. If they were inconsistent, then the computed
    value must be further converted to the correct real kind. Fortran does
    all that conversion work for you by default. If you want the conversions
    to be done differently, then you can use INT() and REAL() intrinsic
    functions to make all of it explicit, and you can add additional
    parentheses to force specific orders of evaluation of the subexpressions.

    $.02 -Ron Shepard

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John@21:1/5 to All on Sun Mar 20 15:09:05 2022
    So the OP could have just been told to use

    zi = cos( (2*(i-1)+1)*4*atan(1.0d0)/ (2*m) )

    as long as he does not use large values of I and M but it would not have
    been nearly as edifying :>.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to John on Sun Mar 20 15:38:06 2022
    On Sunday, March 20, 2022 at 3:09:08 PM UTC-7, John wrote:
    So the OP could have just been told to use

    zi = cos( (2*(i-1)+1)*4*atan(1.0d0)/ (2*m) )

    as long as he does not use large values of I and M but it would not have
    been nearly as edifying :>.

    Well, the question asked about DCOS.

    It could have asked about all the different ways to evaluate the given expression, or one close to it. Sometimes the actual answer depends
    on more than is given. We don't know where this is being used, and so
    not exactly what the right answer is.

    It is possible, for example, that it needs to match exactly, or close
    enough, to some expression using 3.1415927. In that case, a more
    exact approximate pi doesn't help.

    If it doesn't need to be evaluated for a large number of different I
    or M, then a look-up table might be a good solution.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to All on Sun Mar 20 15:25:27 2022
    In case anyone didn't try it, if you ask "Alexa, what is the tangent of 90 degrees?"
    you get 677731.1456.

    I didn't actually try to figure out where that came from.

    The first thing that routines like COS or TAN do, is to divide by some
    multiple of pi, maybe pi/2 to find the octant of the angle. There is a
    good chance that, even if you use the most accurate pi for the precision
    in use, that it isn't the hoped-for exact multiple.

    Some languages have degree trigonometric functions which make this
    a little easier to get right, when the actual source of the argument isn't
    in radians. Multiplying by pi, and then dividing by pi/2, isn't the best
    way to make things come out right.

    I thought that they were in a more recent version of Fortran, but I don't see them in one that I have available.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John@21:1/5 to John on Sun Mar 20 15:25:44 2022
    On Sunday, March 20, 2022 at 6:09:08 PM UTC-4, John wrote:
    So the OP could have just been told to use

    zi = cos( (2*(i-1)+1)*4*atan(1.0d0)/ (2*m) )

    as long as he does not use large values of I and M but it would not have
    been nearly as edifying :>.

    Maybe with a test for M=0 :>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John@21:1/5 to All on Sun Mar 20 16:17:08 2022
    On Sunday, March 20, 2022 at 6:25:29 PM UTC-4, gah4 wrote:
    In case anyone didn't try it, if you ask "Alexa, what is the tangent of 90 degrees?"
    you get 677731.1456.

    I didn't actually try to figure out where that came from.

    The first thing that routines like COS or TAN do, is to divide by some multiple of pi, maybe pi/2 to find the octant of the angle. There is a
    good chance that, even if you use the most accurate pi for the precision
    in use, that it isn't the hoped-for exact multiple.

    Some languages have degree trigonometric functions which make this
    a little easier to get right, when the actual source of the argument isn't
    in radians. Multiplying by pi, and then dividing by pi/2, isn't the best
    way to make things come out right.

    I thought that they were in a more recent version of Fortran, but I don't see them in one that I have available.

    Regarding Alexis not knowing what an undefined (or infinite) value is -- Nobody is perfect. Before you cast any stones too hard you might want to try your Fortran compiler. At least one seems to thing Alexis is "right" for 64 bit floats ...

    program nobody_is_perfect
    use, intrinsic :: iso_fortran_env, only : real_kinds,real32,real64,real128 implicit none

    write(*,*) tan(2*atan(1.0_real32))
    write(*,*) tan(2*atan(1.0_real64))
    write(*,*) tan(2*atan(1.0_real128))

    block
    integer :: lun, i
    character(len=:),allocatable :: scratch_(:)
    scratch_=[ CHARACTER(LEN=128) :: &
    'scale=1002',& 'pi=3.141592653589793238462643383279502884197169399375105820974944592307\',& '81640628620899862803482534211706798214808651328230664709384460955058\',& '22317253594081284811174502841027019385211055596446229489549303819644\',& '28810975665933446128475648233786783165271201909145648566923460348610\',& '45432664821339360726024914127372458700660631558817488152092096282925\',& '40917153643678925903600113305305488204665213841469519415116094330572\',& '70365759591953092186117381932611793105118548074462379962749567351885\',& '75272489122793818301194912983367336244065664308602139494639522473719\',& '07021798609437027705392171762931767523846748184676694051320005681271\',& '45263560827785771342757789609173637178721468440901224953430146549585\',& '37105079227968925892354201995611212902196086403441815981362977477130\',& '99605187072113499999983729780499510597317328160963185950244594553469\',& '08302642522308253344685035261931188171010003137838752886587533208381\',& '42061717766914730359825349042875546873115956286388235378759375195778\',& '18577805321712268066130019278766111959092164201988',&
    's(pi/2)/c(pi/2)',&
    '']
    open(file='_scratch',newunit=lun) write(lun,'(a)')(trim(scratch_(i)),i=1,size(scratch_))
    call execute_command_line('bc -l < _scratch')
    end block

    end program nobody_is_perfect

    -2.2877332E+07
    1.633123935319537E+016
    2.306323558737156172766198381637374E+0034 14492753623188405797101449275362318840579710144927536231884057971014\ 49275362318840579710144927536231884057971014492753623188405797101449\ 27536231884057971014492753623188405797101449275362318840579710144927\ 53623188405797101449275362318840579710144927536231884057971014492753\ 62318840579710144927536231884057971014492753623188405797101449275362\ 31884057971014492753623188405797101449275362318840579710144927536231\ 88405797101449275362318840579710144927536231884057971014492753623188\ 40579710144927536231884057971014492753623188405797101449275362318840\ 57971014492753623188405797101449275362318840579710144927536231884057\ 97101449275362318840579710144927536231884057971014492753623188405797\ 10144927536231884057971014492753623188405797101449275362318840579710\ 14492753623188405797101449275362318840579710144927536231884057971014\ 49275362318840579710144927536231884057971014492753623188405797101449\ 27536231884057971014492753623188405797101449275362318840579710144927\ 5362318840579710144927536231884057971014492753623.188405797101449275\ 36231884057971014492753623188405797101449275362318840579710144927536\ 23188405797101449275362318840579710144927536231884057971014492753623\ 18840579710144927536231884057971014492753623188405797101449275362318\ 84057971014492753623188405797101449275362318840579710144927536231884\ 05797101449275362318840579710144927536231884057971014492753623188405\ 79710144927536231884057971014492753623188405797101449275362318840579\ 71014492753623188405797101449275362318840579710144927536231884057971\ 01449275362318840579710144927536231884057971014492753623188405797101\ 44927536231884057971014492753623188405797101449275362318840579710144\ 92753623188405797101449275362318840579710144927536231884057971014492\ 75362318840579710144927536231884057971014492753623188405797101449275\ 36231884057971014492753623188405797101449275362318840579710144927536\ 23188405797101449275362318840579710144927536231884057971014492753623\ 18840579710144927536231884057971014492753623188405797101449275362318\ 84057971014492753623188405797101

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John@21:1/5 to All on Sun Mar 20 16:31:34 2022
    As regards tand(90.0) gfortran and ifortran do get that "right", but nvfortran does not;
    with versions that have it, so I am not quite being fair; but I really do not test most intrinsics
    near their edges, having learned that the hard way long ago.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to Ron Shepard on Sun Mar 20 20:14:59 2022
    On Monday, March 21, 2022 at 5:48:41 AM UTC+11, Ron Shepard wrote:
    On 3/19/22 6:18 PM, ritchie31 wrote:
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))

    but I got:

    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision

    Any help is appreciated.
    Regards
    Wow, there is a lot to unpack in that statement, and many of the
    suggestions in this thread are off mark.

    First, it does not matter what is the type or kind of ZI. The expression
    on the right is evaluated as it stands regardless.

    Second, you almost certainly should not be using specific intrinsic functions such as DCOS, FLOAT, DFLOAT, DBLE,
    .
    DBLE is a perfectly good intrinsic for converting to double precision. Furthermore, it is generic, and not of the same ilk as DCOS,
    which is the name of the specific function.
    .
    and so on as many have
    suggested. There are times to use those kinds of functions, when
    purposely doing mixed-precision arithmetic, but your application is
    probably not one of those.

    So how should this be written if you want to have simple and robust
    code? First, the value of PI in the expression above is single
    precision. That is, it is the default real kind. If you want extended precision, then you should either declare the constant appropriately or
    you should specify the appropriate kind of the literal constant and add
    in the missing digits. Let's do it like this, not because this is
    inherently better than other approaches, but because no one else has suggested this yet.

    integer, parameter :: wp = selected_real_kind(14)
    REAL(WP), PARAMETER:: PI = 4 * ATAN(1.0_wp)

    The wp parameter is appropriate for double precision on many machines,
    but that is a way to specify the minimum precision independently of what your compiler thinks is the default. That is more or less the modern standard equivalent to REAL*8. You could also declare things like

    integer, parameter :: wp = kind(1.0d0)

    to force the working precision to be what your compiler thinks is double precision. Or, you could declare it as

    integer, parameter :: wp = kind(ZI)

    where ZI has been declared elsewhere, maybe in a module, but you might
    not know what it is, you just know that you want to be consistent with
    that kind. With the appropriate kind defined, you could also specify the literal constant as, for example,

    3.1415926535897931_wp

    4*atan(1.0d0) is better, especially when defined as with the
    PARAMETER attribute as defined above, as tan is then not executed at run time.

    either in a parameter definition or in the original expression itself. I don't really recommend that latter option, but if you wanted to do that,
    it would at least be better than specifying the literal constant to have
    the incorrect kind.

    In any case, once PI is defined to be of the correct type and kind for
    the expression you want to evaluate, and to have the correct value for
    that kind. Then you can evaluate the expression as

    ZI = COS( (2*( I - 1) + 1) * PI / (2*M))
    .
    Groan!
    As has been pointed out already, 2*(i-1) and 2*M can overflow.
    .
    The COS intrinsic is generic, so it evaluates its result to be
    consistent with whatever its argument is. What is that? Fortran has well defined rules for evaluating expressions of mixed type. In that
    expression, the (2*(I-1)+1) will be evaluated as an integer expression because it is enclosed in parentheses. The kind will be KIND(I), which
    is probably whatever the compiler thinks is the default integer kind. If
    the values don't get too big, that will be fine. If they get up around
    10**9 or so, then you might need to worry about integer overflow, which
    is usually silent at runtime, so you should beware of that. Similarly,
    the (2*M) part of the expression is also evaluated as an integer
    expression of KIND(M).
    .
    and that can overflow too.

    Without further knowledge of the declarations,
    that is all that we can say about the integer factors in the expression.
    If I or M are nondefault kind, say they are 64-bit integers, then the expressions will be evaluated with the higher precision of that kind or
    the default kind. That is, either the value of I will be converted to
    the default kind, or the default kind values of 2 and 1 will be
    converted to the declared kind of I or M. The language gives you control over those conversions if you don't want the default behavior. The
    advantage of avoiding the specific intrinsic functions is that in the
    future if the kind values need to change, say because some compiler has different defaults, then you only need to change the wp parameter declaration to get the correct results, you don't need to go back into
    the code and change each occurrence in each expression of a
    kind-specific intrinsic function. If you take care and write your code
    the right way, then that wp parameter can be changed in a single place,
    and that change will propagate throughout your entire program with no further manual changes.

    Then an expression equivalent to

    K*PI/L

    is evaluated, where K and L are the values of those integer expressions
    of their appropriate kinds. The compiler is free to evaluate that in
    either of two ways, (K*PI)/L or as K*(PI/L). In the first case, the
    value of K is converted to a real value with the same kind as PI, the multiplication is done with that precision. Then the value of L is
    converted to real with kind(PI) and the final division is performed. The other option is to convert L first, then divide, then convert K, and
    then multiply the result. There usually isn't any need to specify which
    of those are chosen, so you can let the compiler decide. It might be
    able to optimize those operations a little by reusing a register value,
    or perhaps by reusing a previous conversion from a nearby statement. You
    may not get the same value for those two expressions, but they should be
    the same except possibly for the last bit or two, which is really all
    you can expect from floating point arithmetic.

    Some programmers like to specify type conversions explicitly.
    Particularly those using other languages with different implicit
    conversion semantics. In that case, then one might write the original expression as something like

    ZI = COS( REAL(2*(I-1)+1,KIND=wp) * PI / REAL(2*M,KIND=wp) )
    .
    Groan! That's no better than the above, because 2*(i-1) and 2*M
    can overflow, because the arguments are evaluated first as integer
    expressions, before converting to REAL.
    .
    Others prefer the shorter version. The important point though is that
    this longer expression evaluation does not require any more effort than
    the shorter expression, it will compile to exactly the same
    instructions. It is just specifying explicitly what the compiler is
    required already to do implicitly.

    In any case, you then have the real argument evaluated without
    significant loss of precision for the COS() evaluation. COS is generic,
    so it takes whatever KIND it argument has, and evaluates the result in
    that precision. At this point, if PI has been declared incorrectly, or
    if it had been specified with the wrong kind as in the original code,
    then it would produce results with that wrong precision. But if PI has
    been declared correctly, then it will be evaluated with the correct precision, no less and no more.

    After COS() is evaluated, then the value is assigned to the ZI variable.
    If your declarations were consistent, then that assignment is just a register to memory copy. If they were inconsistent, then the computed
    value must be further converted to the correct real kind. Fortran does
    all that conversion work for you by default. If you want the conversions
    to be done differently, then you can use INT() and REAL() intrinsic functions to make all of it explicit, and you can add additional
    parentheses to force specific orders of evaluation of the subexpressions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to John on Sun Mar 20 20:25:58 2022
    On Monday, March 21, 2022 at 4:46:01 AM UTC+11, John wrote:
    so to summarize, using an arbitrary precision calculation from the
    GNU/Linux version of bc(1) and some somewhat arbitrary I and M values to
    get a few reference values:

    scale=50 pi=3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709

    i=3
    m=8
    c( (2*(i-1)+1)*pi/ (2*m) )

    i=30
    m=30
    c( (2*(i-1)+1)*pi/ (2*m) )

    i=2147483647
    m=2147483647
    c( (2*(i-1)+1)*pi/ (2*m) )

    i=2147483647/2+1000
    m=2147483647/2+1234
    c( (2*(i-1)+1)*pi/ (2*m) )
    ```
    we get

    .55557023301960222474283081394853287437493719075480 -.99862953475457387378449205843943658059095229076778 -.99999999999999999973248383642001669587197950999122 -.99999999999976462804957484993760994845013547247662

    And then compare the original with a minimal change from FLOAT to DFLOAT
    to the simplest generic syntax and a statement corrected to explicitly
    handle all type conversions to double precision we get


    program show
    ! using an appropriate kind instead of explicitly using DOUBLE PRECISION integer,parameter :: dp=kind(0.0d0)
    ! getting a more accurate representation of PI appropriate for the KIND used
    real(kind=dp),parameter :: PI=4*atan(1.0_dp)
    integer :: i,m
    real(kind=dp) :: zi, zi_old
    i=3
    m=8
    call printme()
    i=30
    m=30
    call printme()
    i=huge(0)
    m=huge(0)
    call printme()
    i=huge(0)/2+1000
    m=huge(0)/2+1234
    call printme()

    contains

    subroutine printme()
    ! convert integers early to prevent overflow
    write(*,*)'I=',i,'M=',m
    zi = cos( (2*real(i-1,kind=dp)+1)*PI/ (2*real(m,kind=dp)) )
    write(*,*)zi

    ! using generic and simple statement with just PI double precision write(*,*)cos( (2*(i-1)+1)*PI/ (2*m) )

    ! original except change FLOAT() to DFLOAT()
    ZI_old = DCOS(DFLOAT(2*( I - 1) + 1)*3.1415927/DFlOAT(2*M)) write(*,*)zi_old

    end subroutine printme

    end program show


    I= 3 M= 8
    0.555570233019602
    0.555570233019602
    0.555570210304169
    I= 30 M= 30
    -0.998629534754574
    -0.998629534754574
    -0.998629539253669
    I= 2147483647 M= 2147483647
    -1.00000000000000
    .
    integer overflow occurs here, attempting to evaluate 2*(i-1) or 2*M,
    and no further values are printed.
    Try turning on checks for integer overflow.

    -1.836970198721030E-016
    1.311341700055869E-007
    I= 1073742823 M= 1073741828
    -0.999999999995767
    -0.999999999995767
    -0.999999999996017

    compared to the "reference" values

    .55557023301960222474283081394853287437493719075480 -.99862953475457387378449205843943658059095229076778 -.99999999999999999973248383642001669587197950999122 -.99999999999976462804957484993760994845013547247662

    So a simple statement using generics (that happens to cause automatic promotion) can get good answers over a wide range of input values
    and is much more readable; but to harden the routine over the entire
    range of values for integer inputs and to not use "hidden" conversions
    it is best to not depend on automatic promotion of variables as all,
    possibly introducing new variables to make it more readable, such as

    real(kind=dp) :: ri, rm
    ri=i
    rm=m
    So the summary conclusion seems to be to avoid implicit conversion
    entirely? There are times where integers make it much more explicit
    that the compiler can optimize certain calculations, I would say.

    ! CONCENSUS ???
    program show
    ! using an appropriate kind instead of explicitly using DOUBLE PRECISION integer,parameter :: dp=kind(0.0d0)
    ! getting a more accurate representation of PI appropriate for the KIND used
    real(kind=dp),parameter :: PI=4*atan(1.0_dp)
    integer :: i,m
    real(kind=dp) :: zi, ri, rm
    i=3
    m=8

    ! no implicit type conversions avoids several issues, such as inadvertent
    ! integer overflow
    ri=real(i,kind=dp)
    rm=real(m,kind=dp)
    zi=cos( (2.0_dp*(ri-1.0_dp)+1.0_dp)*PI/ (2.0_dp*rm) )

    end program show

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to John on Sun Mar 20 20:17:34 2022
    On Monday, March 21, 2022 at 9:09:08 AM UTC+11, John wrote:
    So the OP could have just been told to use

    zi = cos( (2*(i-1)+1)*4*atan(1.0d0)/ (2*m) )
    .
    Not really, because PI is more intelligible than 4*atan(1.0d0),
    and 2*(i-1) and 2*M can overflow.

    as long as he does not use large values of I and M but it would not have
    been nearly as edifying :>.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John@21:1/5 to All on Sun Mar 20 20:54:35 2022
    As mentioned, in addition to silent overflow to truly harden it checks such as a check for M=0 would be needed.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John@21:1/5 to Robin Vowels on Sun Mar 20 20:50:00 2022
    On Sunday, March 20, 2022 at 11:26:00 PM UTC-4, Robin Vowels wrote:
    On Monday, March 21, 2022 at 4:46:01 AM UTC+11, John wrote:
    so to summarize, using an arbitrary precision calculation from the GNU/Linux version of bc(1) and some somewhat arbitrary I and M values to get a few reference values:

    scale=50 pi=3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709

    i=3
    m=8
    c( (2*(i-1)+1)*pi/ (2*m) )

    i=30
    m=30
    c( (2*(i-1)+1)*pi/ (2*m) )

    i=2147483647
    m=2147483647
    c( (2*(i-1)+1)*pi/ (2*m) )

    i=2147483647/2+1000
    m=2147483647/2+1234
    c( (2*(i-1)+1)*pi/ (2*m) )
    ```
    we get

    .55557023301960222474283081394853287437493719075480 -.99862953475457387378449205843943658059095229076778 -.99999999999999999973248383642001669587197950999122 -.99999999999976462804957484993760994845013547247662

    And then compare the original with a minimal change from FLOAT to DFLOAT
    to the simplest generic syntax and a statement corrected to explicitly handle all type conversions to double precision we get


    program show
    ! using an appropriate kind instead of explicitly using DOUBLE PRECISION integer,parameter :: dp=kind(0.0d0)
    ! getting a more accurate representation of PI appropriate for the KIND used
    real(kind=dp),parameter :: PI=4*atan(1.0_dp)
    integer :: i,m
    real(kind=dp) :: zi, zi_old
    i=3
    m=8
    call printme()
    i=30
    m=30
    call printme()
    i=huge(0)
    m=huge(0)
    call printme()
    i=huge(0)/2+1000
    m=huge(0)/2+1234
    call printme()

    contains

    subroutine printme()
    ! convert integers early to prevent overflow
    write(*,*)'I=',i,'M=',m
    zi = cos( (2*real(i-1,kind=dp)+1)*PI/ (2*real(m,kind=dp)) )
    write(*,*)zi

    ! using generic and simple statement with just PI double precision write(*,*)cos( (2*(i-1)+1)*PI/ (2*m) )

    ! original except change FLOAT() to DFLOAT()
    ZI_old = DCOS(DFLOAT(2*( I - 1) + 1)*3.1415927/DFlOAT(2*M)) write(*,*)zi_old

    end subroutine printme

    end program show


    I= 3 M= 8
    0.555570233019602
    0.555570233019602
    0.555570210304169
    I= 30 M= 30
    -0.998629534754574
    -0.998629534754574
    -0.998629539253669
    I= 2147483647 M= 2147483647
    -1.00000000000000
    .
    integer overflow occurs here, attempting to evaluate 2*(i-1) or 2*M,
    and no further values are printed.
    Try turning on checks for integer overflow.
    -1.836970198721030E-016
    1.311341700055869E-007
    I= 1073742823 M= 1073741828
    -0.999999999995767
    -0.999999999995767
    -0.999999999996017

    compared to the "reference" values

    .55557023301960222474283081394853287437493719075480 -.99862953475457387378449205843943658059095229076778 -.99999999999999999973248383642001669587197950999122 -.99999999999976462804957484993760994845013547247662

    So a simple statement using generics (that happens to cause automatic promotion) can get good answers over a wide range of input values
    and is much more readable; but to harden the routine over the entire
    range of values for integer inputs and to not use "hidden" conversions
    it is best to not depend on automatic promotion of variables as all, possibly introducing new variables to make it more readable, such as

    real(kind=dp) :: ri, rm
    ri=i
    rm=m
    So the summary conclusion seems to be to avoid implicit conversion entirely? There are times where integers make it much more explicit
    that the compiler can optimize certain calculations, I would say.

    ! CONCENSUS ???
    program show
    ! using an appropriate kind instead of explicitly using DOUBLE PRECISION integer,parameter :: dp=kind(0.0d0)
    ! getting a more accurate representation of PI appropriate for the KIND used
    real(kind=dp),parameter :: PI=4*atan(1.0_dp)
    integer :: i,m
    real(kind=dp) :: zi, ri, rm
    i=3
    m=8

    ! no implicit type conversions avoids several issues, such as inadvertent ! integer overflow
    ri=real(i,kind=dp)
    rm=real(m,kind=dp)
    zi=cos( (2.0_dp*(ri-1.0_dp)+1.0_dp)*PI/ (2.0_dp*rm) )

    end program show
    Perhaps I should have marked them with a comment, but comparing the reference values to the results
    shows the incorrect errors; I was demonstrating the overflow risk with large values. In
    many cases knowing the range of I and M might indicate there is no overflow risk, but the
    OP did not mention the ranges, so I was intentionally showing that silent overflow can occur
    and produce incorrect errors, hence the use of I=huge(0) and M=huge(0) in particular and the explicit type
    conversions in the "concensus???" example.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to gah4@u.washington.edu on Mon Mar 21 06:38:27 2022
    gah4 <gah4@u.washington.edu> schrieb:
    In case anyone didn't try it, if you ask "Alexa, what is the tangent of 90 degrees?"
    you get 677731.1456.

    I didn't actually try to figure out where that came from.

    The first thing that routines like COS or TAN do, is to divide by some multiple of pi, maybe pi/2 to find the octant of the angle. There is a
    good chance that, even if you use the most accurate pi for the precision
    in use, that it isn't the hoped-for exact multiple.

    Some languages have degree trigonometric functions which make this
    a little easier to get right, when the actual source of the argument isn't
    in radians.

    Fortran 202x will contain the functions ACOSD, ASIND, ATAND,
    ATAN2D, COSD, SIND, and TAND.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From DP@21:1/5 to All on Mon Mar 21 04:08:44 2022
    Le samedi 19 mars 2022 à 23:18:29 UTC, ritchie31 a écrit :
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))

    but I got:

    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision

    Any help is appreciated.
    Regards

    The angle

    "FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M)"

    is heavy in superfluous function calls and operations. It can be simplified as
    "(I - 0.5D0)*PI/M"
    where PI = 4D0*ATAN(1D0)
    has been calculated as a parameter as explained in other posts.

    Dan

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to All on Mon Mar 21 05:23:15 2022
    On Sunday, March 20, 2022 at 11:38:30 PM UTC-7, Thomas Koenig wrote:

    (snip, I wrote)

    Some languages have degree trigonometric functions which make this
    a little easier to get right, when the actual source of the argument isn't in radians.

    Fortran 202x will contain the functions ACOSD, ASIND, ATAND,
    ATAN2D, COSD, SIND, and TAND.

    I thought I was remembering that, but couldn't remember which one.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Gary Scott@21:1/5 to All on Mon Mar 21 10:01:51 2022
    On 3/21/2022 7:23 AM, gah4 wrote:
    On Sunday, March 20, 2022 at 11:38:30 PM UTC-7, Thomas Koenig wrote:

    (snip, I wrote)

    Some languages have degree trigonometric functions which make this
    a little easier to get right, when the actual source of the argument isn't >>> in radians.

    Fortran 202x will contain the functions ACOSD, ASIND, ATAND,
    ATAN2D, COSD, SIND, and TAND.

    I thought I was remembering that, but couldn't remember which one.
    Only 35 years late to my need :)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to Thomas Koenig on Mon Mar 21 07:49:00 2022
    On Monday, March 21, 2022 at 5:38:30 PM UTC+11, Thomas Koenig wrote:
    gah4 <ga...@u.washington.edu> schrieb:
    In case anyone didn't try it, if you ask "Alexa, what is the tangent of 90 degrees?"
    you get 677731.1456.

    I didn't actually try to figure out where that came from.

    The first thing that routines like COS or TAN do, is to divide by some multiple of pi, maybe pi/2 to find the octant of the angle. There is a
    good chance that, even if you use the most accurate pi for the precision
    in use, that it isn't the hoped-for exact multiple.

    Some languages have degree trigonometric functions which make this
    a little easier to get right, when the actual source of the argument isn't in radians.
    Fortran 202x will contain the functions ACOSD, ASIND, ATAND,
    ATAN2D, COSD, SIND, and TAND.
    .
    PL/I has had them for 55 years.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From steve kargl@21:1/5 to John on Mon Mar 21 16:41:33 2022
    John wrote:

    As regards tand(90.0) gfortran and ifortran do get that "right", but nvfortran does not;
    with versions that have it, so I am not quite being fair; but I really do not test most intrinsics
    near their edges, having learned that the hard way long ago.

    If you find a corner case with sind(), cosd(), or tand() in gfortran, please file a bug report.

    % head -3 gcc/libgfortran/intrinsics/trigd.c
    /* Implementation of the degree trignometric functions COSD, SIND, TAND.
    Copyright (C) 2020-2022 Free Software Foundation, Inc.
    Contributed by Steven G. Kargl <kargl@gcc.gnu.org>

    --
    steve

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From steve kargl@21:1/5 to Spiros Bousbouras on Mon Mar 21 19:07:45 2022
    Spiros Bousbouras wrote:

    On Mon, 21 Mar 2022 16:41:33 -0000 (UTC)
    steve kargl <sgk@REMOVEtroutmask.apl.washington.edu> wrote:
    If you find a corner case with sind(), cosd(), or tand() in gfortran,
    please file a bug report.

    % head -3 gcc/libgfortran/intrinsics/trigd.c
    /* Implementation of the degree trignometric functions COSD, SIND, TAND.
    Copyright (C) 2020-2022 Free Software Foundation, Inc.
    Contributed by Steven G. Kargl <kargl@gcc.gnu.org>

    Well , "trignometric" is a typo.

    Thanks. Can you submit a bug report so that a gfortran
    contributor can fix it? I no longer commit changes nor
    contribute to gfortran.

    PS: I would not call a typo in a comment a "corner case",
    but your attention to details is appreciated.

    PPS: If you have ever used gfortran, "You're Welcomed".

    --
    steve

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Spiros Bousbouras@21:1/5 to steve kargl on Mon Mar 21 18:36:25 2022
    On Mon, 21 Mar 2022 16:41:33 -0000 (UTC)
    steve kargl <sgk@REMOVEtroutmask.apl.washington.edu> wrote:
    If you find a corner case with sind(), cosd(), or tand() in gfortran,
    please file a bug report.

    % head -3 gcc/libgfortran/intrinsics/trigd.c
    /* Implementation of the degree trignometric functions COSD, SIND, TAND.
    Copyright (C) 2020-2022 Free Software Foundation, Inc.
    Contributed by Steven G. Kargl <kargl@gcc.gnu.org>

    Well , "trignometric" is a typo.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ron Shepard@21:1/5 to All on Mon Mar 21 14:43:19 2022
    On 3/21/22 6:08 AM, DP wrote:
    Le samedi 19 mars 2022 à 23:18:29 UTC, ritchie31 a écrit :
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))

    but I got:

    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision

    Any help is appreciated.
    Regards

    The angle

    "FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M)"

    is heavy in superfluous function calls and operations. It can be simplified as
    "(I - 0.5D0)*PI/M"
    where PI = 4D0*ATAN(1D0)
    has been calculated as a parameter as explained in other posts.

    This looks like a good way to rewrite the expression. This eliminates
    any possibility of integer overflow during the evaluation of the
    expression, and also eliminates the extra arithmetic operations.

    As in my previous comment, I would recommend using a kind parameter,
    such as wp, to specify the kinds rather than hardwiring them to double precision. REAL*8 usually does mean double precision, but I have used
    several computers with long words that mapped REAL*8 to single
    precision, and also many compilers allow changing the default kinds with options. The fortran KIND approach eliminates all of that ambiguity in
    the source code. So with those comments in mind, I might suggest the
    expression

    (I - 0.5_wp) * PI / M

    where PI has already been declared to have the wp KIND. This results in consistent conversions of types using the standard fortran semantics. If
    you want to make the conversions explicit, then

    (real(I,kind=wp) - 0.5_wp) * PI / real(M,kind=wp)

    This longer expression should compile to exactly the same instructions
    because it is doing exactly the same conversions as required by the
    default semantics.

    $.02 -Ron Shepard

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to Ron Shepard on Mon Mar 21 17:42:11 2022
    On Tuesday, March 22, 2022 at 6:43:23 AM UTC+11, Ron Shepard wrote:
    On 3/21/22 6:08 AM, DP wrote:
    Le samedi 19 mars 2022 à 23:18:29 UTC, ritchie31 a écrit :
    Can anyone please explain what is wrong here?

    I and M are integers and ZI is IMPLICIT REAL*8
    So, I think this is okay the following line:

    ZI = DCOS(FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M))

    but I got:

    Error: ‘x’ argument of ‘dcos’ intrinsic at (1) must be double precision

    Any help is appreciated.
    Regards

    The angle

    "FLOAT(2*( I - 1) + 1)*3.1415927/FlOAT(2*M)"

    is heavy in superfluous function calls and operations. It can be simplified as
    "(I - 0.5D0)*PI/M"
    where PI = 4D0*ATAN(1D0)

    4*ATAN(1.0D0) is sufficient. KISS !

    has been calculated as a parameter as explained in other posts.
    This looks like a good way to rewrite the expression. This eliminates
    any possibility of integer overflow during the evaluation of the
    expression, and also eliminates the extra arithmetic operations.

    As in my previous comment, I would recommend using a kind parameter,
    such as wp, to specify the kinds rather than hardwiring them to double precision. REAL*8 usually does mean double precision, but I have used several computers with long words that mapped REAL*8 to single
    precision, and also many compilers allow changing the default kinds with options. The fortran KIND approach eliminates all of that ambiguity in
    the source code. So with those comments in mind, I might suggest the expression

    (I - 0.5_wp) * PI / M

    where PI has already been declared to have the wp KIND. This results in consistent conversions of types using the standard fortran semantics. If
    you want to make the conversions explicit, then

    (real(I,kind=wp) - 0.5_wp) * PI / real(M,kind=wp)

    This longer expression should compile to exactly the same instructions because it is doing exactly the same conversions as required by the
    default semantics.

    It's obfuscation of what is otherwise a simple expression.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)