Skip to content

Commit d477d5a

Browse files
committed
Add all_close function in stdlib_math.
1 parent e583de5 commit d477d5a

File tree

7 files changed

+160
-5
lines changed

7 files changed

+160
-5
lines changed

doc/specs/stdlib_math.md

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,4 +405,64 @@ program demo_math_is_close
405405
call check(all(is_close(x, [2.0, 2.0])), msg="all(is_close(x, [2.0, 2.0])) failed.", warn=.true.)
406406
!! all(is_close(x, [2.0, 2.0])) failed.
407407
end program demo_math_is_close
408-
```
408+
```
409+
410+
### `all_close`
411+
412+
#### Description
413+
414+
Returns a boolean scalar where two arrays are element-wise equal within a tolerance, behaves like `all(is_close(a, b [, rel_tol, abs_tol]))`.
415+
416+
#### Syntax
417+
418+
`bool = [[stdlib_math(module):all_close(interface)]] (a, b [, rel_tol, abs_tol])`
419+
420+
#### Status
421+
422+
Experimental.
423+
424+
#### Class
425+
426+
Impure function.
427+
428+
#### Arguments
429+
430+
`a`: Shall be a `real/complex` array.
431+
This argument is `intent(in)`.
432+
433+
`b`: Shall be a `real/complex` array.
434+
This argument is `intent(in)`.
435+
436+
`rel_tol`: Shall be a `real` scalar.
437+
This argument is `intent(in)` and `optional`, which is `1.0e-9` by default.
438+
439+
`abs_tol`: Shall be a `real` scalar.
440+
This argument is `intent(in)` and `optional`, which is `0.0` by default.
441+
442+
Note: All `real/complex` arguments must have same `kind`.
443+
If the value of `rel_tol/abs_tol` is negative (not recommended),
444+
it will be corrected to `abs(rel_tol/abs_tol)` by the internal process of `all_close`.
445+
446+
#### Result value
447+
448+
Returns a `logical` scalar.
449+
450+
#### Example
451+
452+
```fortran
453+
program demo_math_all_close
454+
use stdlib_math, only: all_close
455+
use stdlib_error, only: check
456+
real :: x(2) = [1, 2], random(4, 4)
457+
complex :: z(4, 4)
458+
459+
call check(all_close(x, [2.0, 2.0], rel_tol=1.0e-6, abs_tol=1.0e-3), &
460+
msg="all_close(x, [2.0, 2.0]) failed.", warn=.true.)
461+
!! all_close(x, [2.0, 2.0]) failed.
462+
463+
call random_number(random(4, 4))
464+
z = 1.0
465+
print *, all_close(z+1.0e-11*random, z) !! T
466+
467+
end program demo_math_all_close
468+
```

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ set(fppFiles
3434
stdlib_math_logspace.fypp
3535
stdlib_math_arange.fypp
3636
stdlib_math_is_close.fypp
37+
stdlib_math_all_close.fypp
3738
stdlib_string_type.fypp
3839
stdlib_string_type_constructor.fypp
3940
stdlib_strings_to_string.fypp

src/stdlib_math.fypp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module stdlib_math
1111
public :: clip, linspace, logspace
1212
public :: EULERS_NUMBER_SP, EULERS_NUMBER_DP, EULERS_NUMBER_QP
1313
public :: DEFAULT_LINSPACE_LENGTH, DEFAULT_LOGSPACE_BASE, DEFAULT_LOGSPACE_LENGTH
14-
public :: arange, is_close
14+
public :: arange, is_close, all_close
1515

1616
integer, parameter :: DEFAULT_LINSPACE_LENGTH = 100
1717
integer, parameter :: DEFAULT_LOGSPACE_LENGTH = 50
@@ -281,7 +281,7 @@ module stdlib_math
281281

282282
!> Version: experimental
283283
!>
284-
!> Determines whether the values of `a` and `b` are close.
284+
!> Returns a boolean scalar/array where two scalar/arrays are element-wise equal within a tolerance.
285285
!> ([Specification](../page/specs/stdlib_logic.html#is_close))
286286
interface is_close
287287
#:set RC_KINDS_TYPES = REAL_KINDS_TYPES + CMPLX_KINDS_TYPES
@@ -294,6 +294,20 @@ module stdlib_math
294294
#:endfor
295295
end interface is_close
296296

297+
!> Version: experimental
298+
!>
299+
!> Returns a boolean scalar where two arrays are element-wise equal within a tolerance.
300+
!> ([Specification](../page/specs/stdlib_logic.html#all_close))
301+
interface all_close
302+
#:set RC_KINDS_TYPES = REAL_KINDS_TYPES + CMPLX_KINDS_TYPES
303+
#:for k1, t1 in RC_KINDS_TYPES
304+
logical module function all_close_${t1[0]}$${k1}$(a, b, rel_tol, abs_tol) result(close)
305+
${t1}$, intent(in) :: a(..), b(..)
306+
real(${k1}$), intent(in), optional :: rel_tol, abs_tol
307+
end function all_close_${t1[0]}$${k1}$
308+
#:endfor
309+
end interface all_close
310+
297311
contains
298312

299313
#:for k1, t1 in IR_KINDS_TYPES

src/stdlib_math_all_close.fypp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#:include "common.fypp"
2+
#:set RANKS = range(1, MAXRANK + 1)
3+
#:set RC_KINDS_TYPES = REAL_KINDS_TYPES + CMPLX_KINDS_TYPES
4+
5+
submodule (stdlib_math) stdlib_math_all_close
6+
7+
implicit none
8+
9+
contains
10+
11+
#:def inrank(r1)
12+
rank(${r1}$)
13+
select rank(b)
14+
rank(${r1}$)
15+
close = all(is_close(a, b, rel_tol, abs_tol))
16+
rank default
17+
error stop "*<ERROR>* The ranks of `a` and `b` in `all_close` are not equal."
18+
end select
19+
#:enddef
20+
21+
#:for k1, t1 in RC_KINDS_TYPES
22+
logical module function all_close_${t1[0]}$${k1}$(a, b, rel_tol, abs_tol) result(close)
23+
24+
${t1}$, intent(in) :: a(..), b(..)
25+
real(${k1}$), intent(in), optional :: rel_tol, abs_tol
26+
27+
select rank(a)
28+
29+
#:for r1 in RANKS
30+
$:inrank(r1)
31+
#:endfor
32+
33+
rank default
34+
error stop "*<ERROR>* The rank of `a` in `all_close` is too large to be supported."
35+
end select
36+
37+
end function all_close_${t1[0]}$${k1}$
38+
#:endfor
39+
40+
end submodule stdlib_math_all_close

src/tests/math/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ ADDTEST(stdlib_math)
22
ADDTEST(linspace)
33
ADDTEST(logspace)
44
ADDTEST(math_arange)
5-
ADDTEST(math_is_close)
5+
ADDTEST(math_is_close)
6+
ADDTEST(math_all_close)

src/tests/math/Makefile.manual

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
PROGS_SRC = test_stdlib_math.f90 test_linspace.f90 test_logspace.f90 \
22
test_math_arange.f90 \
3-
test_math_is_close.f90
3+
test_math_is_close.f90 \
4+
test_math_all_close.f90
45

56

67
include ../Makefile.manual.test.mk
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
program tester
2+
3+
use stdlib_math, only: all_close
4+
use stdlib_error, only: check
5+
implicit none
6+
7+
call test_math_all_close_real
8+
call test_math_all_close_complex
9+
print *, "All tests in `test_math_all_close` passed."
10+
11+
contains
12+
13+
subroutine test_math_all_close_real
14+
15+
real :: x(4, 4), random(4, 4)
16+
17+
call random_number(random)
18+
x = 1.0
19+
20+
call check(all_close(x+1.0e-11*random, x), msg="REAL: all_close(x+1.0e-11*random, x) failed.")
21+
call check(all_close(x+1.0e-5 *random, x), msg="REAL: all_close(x+1.0e-5 *random, x) failed.", warn=.true.)
22+
23+
end subroutine test_math_all_close_real
24+
25+
subroutine test_math_all_close_complex
26+
27+
real :: random(4, 4)
28+
complex :: x(4, 4)
29+
30+
call random_number(random)
31+
x = 1.0
32+
33+
call check(all_close(x+1.0e-11*random, x), msg="CMPLX: all_close(x+1.0e-11*random, x)")
34+
call check(all_close(x+1.0e-5 *random, x), msg="CMPLX: all_close(x+1.0e-5 *random, x) failed.", warn=.true.)
35+
36+
end subroutine test_math_all_close_complex
37+
38+
end program tester

0 commit comments

Comments
 (0)