Skip to content

[stdlib_math] add arg/argd/argpi #498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 19, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 130 additions & 1 deletion doc/specs/stdlib_math.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,4 +342,133 @@ program demo_math_arange
print *, arange(0.0,2.0,0.0) !! [0.0,1.0,2.0]. Not recommended: `step` argument is zero!

end program demo_math_arange
```
```

## `arg`

### Status

Experimental

### Class

Elemental function.

### Description

`arg` computes the phase angle (radian version) of `complex` scalar in the interval [-π,π].
The angles in `theta` are such that `z = abs(z)*exp((0.0, theta))`.

### Syntax

`result = [[stdlib_math(module):arg(interface)]](z)`

### Arguments

`z`: Shall be a `complex` scalar/array.
This is an `intent(in)` argument.

### Return value

Returns the `real` type phase angle (radian version) of the `complex` argument `z`.

#### Notes

Although the angle of the complex number `0` is undefined, `arg((0,0))` returns the value `0`.

### Example

```fortran
program demo_math_arg
use stdlib_math, only: arg
print *, arg((0.0, 0.0)) !! 0.0
print *, arg((3.0, 4.0)) !! 0.927
print *, arg(2.0*exp((0.0, 0.5))) !! 0.5
end program demo_math_arg
```

## `argd`

### Status

Experimental

### Class

Elemental function.

### Description

`argd` computes the phase angle (degree version) of `complex` scalar in the interval [-180.0,180.0].
The angles in `theta` are such that `z = abs(z)*exp((0.0, theta*π/180.0))`.

### Syntax

`result = [[stdlib_math(module):argd(interface)]](z)`

### Arguments

`z`: Shall be a `complex` scalar/array.
This is an `intent(in)` argument.

### Return value

Returns the `real` type phase angle (degree version) of the `complex` argument `z`.

#### Notes

Although the angle of the complex number `0` is undefined, `argd((0,0))` returns the value `0`.

### Example

```fortran
program demo_math_argd
use stdlib_math, only: argd
print *, argd((0.0, 0.0)) !! 0.0
print *, argd((3.0, 4.0)) !! 53.1°
print *, argd(2.0*exp((0.0, 0.5))) !! 28.64°
end program demo_math_argd
```

## `argpi`

### Status

Experimental

### Class

Elemental function.

### Description

`argpi` computes the phase angle (circular version) of `complex` scalar in the interval [-1.0,1.0].
The angles in `theta` are such that `z = abs(z)*exp((0.0, theta*π))`.

### Syntax

`result = [[stdlib_math(module):argpi(interface)]](z)`

### Arguments

`z`: Shall be a `complex` scalar/array.
This is an `intent(in)` argument.

### Return value

Returns the `real` type phase angle (circular version) of the `complex` argument `z`.

#### Notes

Although the angle of the complex number `0` is undefined, `argpi((0,0))` returns the value `0`.

### Example

```fortran
program demo_math_argpi
use stdlib_math, only: argpi
print *, argpi((0.0, 0.0)) !! 0.0
print *, argpi((3.0, 4.0)) !! 0.295
print *, argpi(2.0*exp((0.0, 0.5))) !! 0.159
end program demo_math_argpi
```
64 changes: 63 additions & 1 deletion src/stdlib_math.fypp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module stdlib_math
public :: clip, linspace, logspace
public :: EULERS_NUMBER_SP, EULERS_NUMBER_DP, EULERS_NUMBER_QP
public :: DEFAULT_LINSPACE_LENGTH, DEFAULT_LOGSPACE_BASE, DEFAULT_LOGSPACE_LENGTH
public :: arange
public :: arange, arg, argd, argpi

integer, parameter :: DEFAULT_LINSPACE_LENGTH = 100
integer, parameter :: DEFAULT_LOGSPACE_LENGTH = 50
Expand All @@ -22,6 +22,11 @@ module stdlib_math
real(dp), parameter :: EULERS_NUMBER_DP = exp(1.0_dp)
real(qp), parameter :: EULERS_NUMBER_QP = exp(1.0_qp)

!> Useful constants `PI` for `argd/argpi`
#:for k1 in REAL_KINDS
real(kind=${k1}$), parameter :: PI_${k1}$ = 4.0_${k1}$*atan(1.0_${k1}$)
#:endfor

interface clip
#:for k1, t1 in IR_KINDS_TYPES
module procedure clip_${k1}$
Expand Down Expand Up @@ -279,6 +284,36 @@ module stdlib_math
#:endfor
end interface arange

!> Version: experimental
!>
!> `arg` computes the phase angle in the interval [-π,π].
!> ([Specification](../page/specs/stdlib_math.html#arg))
interface arg
#:for k1, t1 in CMPLX_KINDS_TYPES
procedure :: arg_${k1}$
#:endfor
end interface arg

!> Version: experimental
!>
!> `argd` computes the phase angle of degree version in the interval [-180.0,180.0].
!> ([Specification](../page/specs/stdlib_math.html#argd))
interface argd
#:for k1, t1 in CMPLX_KINDS_TYPES
procedure :: argd_${k1}$
#:endfor
end interface argd

!> Version: experimental
!>
!> `argpi` computes the phase angle of IEEE circular version in the interval [-1.0,1.0].
!> ([Specification](../page/specs/stdlib_math.html#argpi))
interface argpi
#:for k1, t1 in CMPLX_KINDS_TYPES
procedure :: argpi_${k1}$
#:endfor
end interface argpi

contains

#:for k1, t1 in IR_KINDS_TYPES
Expand All @@ -292,4 +327,31 @@ contains
end function clip_${k1}$

#:endfor

#:for k1, t1 in CMPLX_KINDS_TYPES
elemental function arg_${k1}$(z) result(result)
${t1}$, intent(in) :: z
real(${k1}$) :: result

result = aimag(log(z))

end function arg_${k1}$

elemental function argd_${k1}$(z) result(result)
${t1}$, intent(in) :: z
real(${k1}$) :: result

result = aimag(log(z))*180.0_${k1}$/PI_${k1}$

end function argd_${k1}$

elemental function argpi_${k1}$(z) result(result)
${t1}$, intent(in) :: z
real(${k1}$) :: result

result = aimag(log(z))/PI_${k1}$

end function argpi_${k1}$
#:endfor

end module stdlib_math
3 changes: 2 additions & 1 deletion src/tests/math/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ADDTEST(stdlib_math)
ADDTEST(linspace)
ADDTEST(logspace)
ADDTEST(math_arange)
ADDTEST(math_arange)
ADDTEST(math_arg)
3 changes: 2 additions & 1 deletion src/tests/math/Makefile.manual
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
PROGS_SRC = test_stdlib_math.f90 test_linspace.f90 test_logspace.f90 \
test_math_arange.f90
test_math_arange.f90 \
test_math_arg.f90


include ../Makefile.manual.test.mk
41 changes: 41 additions & 0 deletions src/tests/math/test_math_arg.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
program tester

real :: tol = 1.0e-3
call test_math_arg_complex
call test_math_argd_complex
call test_math_argpi_complex
print *, "All tests in `test_math_arg` passed."

contains

subroutine test_math_arg_complex
use stdlib_math, only: arg
use stdlib_error, only: check

call check(abs(arg(2.0*exp((0.0e0, 0.5))) - 0.5) < tol, msg="arg(2.0*exp((0.0, 0.5))) failed.")
call check(abs(arg((1.7552, 0.9589)) - 0.5) < tol, msg="arg((1.7552, 0.9589)) failed.")
call check(abs(arg((0.0, 0.0)) - 0.0) < tol, msg="arg((0.0, 0.0)) failed.")

end subroutine test_math_arg_complex

subroutine test_math_argd_complex
use stdlib_math, only: argd
use stdlib_error, only: check

call check(abs(argd(2.0*exp((0.0, 0.5))) - 28.648) < tol, msg="argd(2.0*exp((0.0, 0.5))) failed.")
call check(abs(argd((1.7552, 0.9589)) - 28.648) < tol, msg="argd((1.7552, 0.9589)) failed.")
call check(abs(argd((0.0, 0.0)) - 0.0) < tol, msg="argd((0.0, 0.0)) failed.")

end subroutine test_math_argd_complex

subroutine test_math_argpi_complex
use stdlib_math, only: argpi
use stdlib_error, only: check

call check(abs(argpi(2.0*exp((0.0, 0.5))) - 0.159) < tol, msg="argpi(2.0*exp((0.0, 0.5))) failed.")
call check(abs(argpi((1.7552, 0.9589)) - 0.159) < tol, msg="argpi((1.7552, 0.9589)) failed.")
call check(abs(argpi((0.0, 0.0)) - 0.0) < tol, msg="argpi((0.0, 0.0)) failed.")

end subroutine test_math_argpi_complex

end program tester