Skip to content

Commit 37c84c7

Browse files
authored
assert_approximate switched from absolut compare to relative
- different relative equations are available (https://en.wikipedia.org/wiki/Relative_change_and_difference) - divide by zero protection for *_vec and *_array routines
1 parent 57b5421 commit 37c84c7

File tree

1 file changed

+114
-18
lines changed

1 file changed

+114
-18
lines changed

src/assert_mod.F90

Lines changed: 114 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ module assert_mod
5959
module procedure assert_great_than_real4_array
6060
module procedure assert_great_than_real8_array
6161
end interface assert_great_than
62+
63+
interface get_relative_difference
64+
module procedure get_relative_difference_real4
65+
module procedure get_relative_difference_real8
66+
end interface
67+
68+
real(8), parameter :: eps_default_kind8 = 1d-3
69+
real(4), parameter :: eps_default_kind4 = 1e-3
6270

6371
contains
6472

@@ -580,49 +588,62 @@ subroutine assert_equal_string_array(x, y, file_name, line_number, suite)
580588

581589
end subroutine assert_equal_string_array
582590

583-
subroutine assert_approximate_real4(x, y, file_name, line_number, eps, suite)
591+
subroutine assert_approximate_real4(x, y, file_name, line_number, eps_user, suite)
584592

585593
real(4), intent(in) :: x
586594
real(4), intent(in) :: y
587595
character(*), intent(in), optional :: file_name
588596
integer, intent(in), optional :: line_number
589-
real(4), intent(in), optional :: eps
597+
real(4), intent(in), optional :: eps_user
590598
type(test_suite_type), intent(in), optional :: suite
599+
600+
real(4) :: eps
601+
602+
eps = merge(eps_user, eps_default_kind4, present(eps_user))
591603

592-
call test_case_append_assert('=~', abs(x-y) < merge(eps, 1.0e-10, present(eps)), to_string(x), to_string(y), file_name, line_number, suite)
604+
call test_case_append_assert('=~', abs(x - y) / get_relative_difference(x, y) < eps, to_string(x), to_string(y), file_name, line_number, suite)
593605

594606
end subroutine assert_approximate_real4
595607

596-
subroutine assert_approximate_real8(x, y, file_name, line_number, eps, suite)
608+
subroutine assert_approximate_real8(x, y, file_name, line_number, eps_user, suite)
597609

598610
real(8), intent(in) :: x
599611
real(8), intent(in) :: y
600612
character(*), intent(in), optional :: file_name
601613
integer, intent(in), optional :: line_number
602-
real(8), intent(in), optional :: eps
614+
real(8), intent(in), optional :: eps_user
603615
type(test_suite_type), intent(in), optional :: suite
616+
617+
real(8) :: eps
618+
619+
eps = merge(eps_user, eps_default_kind8, present(eps_user))
604620

605-
call test_case_append_assert('=~', abs(x-y) < merge(eps, 1.0d-10, present(eps)), to_string(x), to_string(y), file_name, line_number, suite)
621+
call test_case_append_assert('=~', abs(x - y) / get_relative_difference(x, y) < eps, to_string(x), to_string(y), file_name, line_number, suite)
606622

607623
end subroutine assert_approximate_real8
608624

609-
subroutine assert_approximate_real4_vec(x, y, file_name, line_number, eps, suite)
625+
subroutine assert_approximate_real4_vec(x, y, file_name, line_number, eps_user, suite)
610626

611627
real(4), intent(in) :: x(:)
612628
real(4), intent(in) :: y(:)
613629
character(*), intent(in), optional :: file_name
614630
integer, intent(in), optional :: line_number
615-
real(4), intent(in), optional :: eps
631+
real(4), intent(in), optional :: eps_user
616632
type(test_suite_type), intent(in), optional :: suite
617633

618634
logical :: passed
619635
integer :: loc, i
636+
real(4) :: eps
637+
638+
eps = merge(eps_user, eps_default_kind8, present(eps_user))
620639

621640
passed = .true.
622641
loc = lbound(x, 1)
623642
if (lbound(x, 1) == lbound(y, 1) .and. ubound(x, 1) == ubound(y, 1)) then
624643
do i = lbound(x, 1), ubound(x, 1)
625-
if (.not. abs(x(i) - y(i)) < merge(eps, 1.0e-10, present(eps))) then
644+
if (.not. abs(x(i) - y(i)) / get_relative_difference(x(i), y(i)) < eps) then
645+
if (get_relative_difference(x(i), y(i)) == 0.0D0) &
646+
& cycle
626647
loc = i
627648
passed = .false.
628649
exit
@@ -634,23 +655,28 @@ subroutine assert_approximate_real4_vec(x, y, file_name, line_number, eps, suite
634655

635656
end subroutine assert_approximate_real4_vec
636657

637-
subroutine assert_approximate_real8_vec(x, y, file_name, line_number, eps, suite)
658+
subroutine assert_approximate_real8_vec(x, y, file_name, line_number, eps_user, suite)
638659

639660
real(8), intent(in) :: x(:)
640661
real(8), intent(in) :: y(:)
641662
character(*), intent(in), optional :: file_name
642663
integer, intent(in), optional :: line_number
643-
real(8), intent(in), optional :: eps
664+
real(8), intent(in), optional :: eps_user
644665
type(test_suite_type), intent(in), optional :: suite
645666

646667
logical :: passed
647668
integer :: loc, i
669+
real(8) :: eps
670+
671+
eps = merge(eps_user, eps_default_kind8, present(eps_user))
648672

649673
passed = .true.
650674
loc = lbound(x, 1)
651675
if (lbound(x, 1) == lbound(y, 1) .and. ubound(x, 1) == ubound(y, 1)) then
652676
do i = lbound(x, 1), ubound(x, 1)
653-
if (.not. abs(x(i) - y(i)) < merge(eps, 1.0d-10, present(eps))) then
677+
if (.not. abs(x(i) - y(i)) / get_relative_difference(x(i), y(i)) < eps) then
678+
if (get_relative_difference(x(i), y(i)) == 0.0D0) &
679+
& cycle
654680
loc = i
655681
passed = .false.
656682
exit
@@ -662,17 +688,20 @@ subroutine assert_approximate_real8_vec(x, y, file_name, line_number, eps, suite
662688

663689
end subroutine assert_approximate_real8_vec
664690

665-
subroutine assert_approximate_real4_array(x, y, file_name, line_number, eps, suite)
691+
subroutine assert_approximate_real4_array(x, y, file_name, line_number, eps_user, suite)
666692

667693
real(4), intent(in) :: x(:, :)
668694
real(4), intent(in) :: y(:, :)
669695
character(*), intent(in), optional :: file_name
670696
integer, intent(in), optional :: line_number
671-
real(4), intent(in), optional :: eps
697+
real(4), intent(in), optional :: eps_user
672698
type(test_suite_type), intent(in), optional :: suite
673699

674700
logical :: passed
675701
integer :: loc_i, loc_j, i, j
702+
real(4) :: eps
703+
704+
eps = merge(eps_user, eps_default_kind4, present(eps_user))
676705

677706
passed = .true.
678707
loc_i = lbound(x, 1)
@@ -681,7 +710,9 @@ subroutine assert_approximate_real4_array(x, y, file_name, line_number, eps, sui
681710
lbound(x, 2) == lbound(y, 2) .and. ubound(x, 2) == ubound(y, 2)) then
682711
do i = lbound(x, 1), ubound(x, 1)
683712
do j = lbound(x, 2), ubound(x, 2)
684-
if (.not. abs(x(i, j) - y(i, j)) < merge(eps, 1.0e-10, present(eps))) then
713+
if (.not. abs(x(i, j) - y(i, j)) / get_relative_difference(x(i, j), y(i, j)) < eps) then
714+
if (get_relative_difference(x(i, j), y(i, j)) == 0.0D0) &
715+
& cycle
685716
loc_i = i
686717
loc_j = j
687718
passed = .false.
@@ -695,17 +726,20 @@ subroutine assert_approximate_real4_array(x, y, file_name, line_number, eps, sui
695726

696727
end subroutine assert_approximate_real4_array
697728

698-
subroutine assert_approximate_real8_array(x, y, file_name, line_number, eps, suite)
729+
subroutine assert_approximate_real8_array(x, y, file_name, line_number, eps_user, suite)
699730

700731
real(8), intent(in) :: x(:, :)
701732
real(8), intent(in) :: y(:, :)
702733
character(*), intent(in), optional :: file_name
703734
integer, intent(in), optional :: line_number
704-
real(8), intent(in), optional :: eps
735+
real(8), intent(in), optional :: eps_user
705736
type(test_suite_type), intent(in), optional :: suite
706737

707738
logical :: passed
708739
integer :: loc_i, loc_j, i, j
740+
real(8) :: eps
741+
742+
eps = merge(eps_user, eps_default_kind8, present(eps_user))
709743

710744
passed = .true.
711745
loc_i = lbound(x, 1)
@@ -714,7 +748,9 @@ subroutine assert_approximate_real8_array(x, y, file_name, line_number, eps, sui
714748
lbound(x, 2) == lbound(y, 2) .and. ubound(x, 2) == ubound(y, 2)) then
715749
do i = lbound(x, 1), ubound(x, 1)
716750
do j = lbound(x, 2), ubound(x, 2)
717-
if (.not. abs(x(i, j) - y(i, j)) < merge(eps, 1.0d-10, present(eps))) then
751+
if (.not. abs(x(i, j) - y(i, j)) / get_relative_difference(x(i, j), y(i, j)) < eps) then
752+
if (get_relative_difference(x(i, j), y(i, j)) == 0.0D0) &
753+
& cycle
718754
loc_i = i
719755
loc_j = j
720756
passed = .false.
@@ -1203,5 +1239,65 @@ subroutine assert_failure(file_name, line_number, suite)
12031239
call test_case_append_assert('failure', .false., 'N/A', 'N/A', file_name, line_number, suite = suite)
12041240

12051241
end subroutine assert_failure
1242+
1243+
real(4) function get_relative_difference_real4(x, y, case)
1244+
1245+
real(4), intent(in) :: x
1246+
real(4), intent(in) :: y
1247+
integer, optional, intent(in) :: case
1248+
1249+
select case (merge(case, 1, present(case)))
1250+
1251+
case (1)
1252+
get_relative_difference_real4 = max(abs(x), abs(y))
1253+
1254+
case (2)
1255+
get_relative_difference_real4 = max(x, y)
1256+
1257+
case (3)
1258+
get_relative_difference_real4 = min(abs(x), abs(y))
1259+
1260+
case (4)
1261+
get_relative_difference_real4 = min(x, y)
1262+
1263+
case (5)
1264+
get_relative_difference_real4 = (x + y) / 2
1265+
1266+
case (6)
1267+
get_relative_difference_real4 = (abs(x) + abs(y)) / 2
1268+
1269+
end select
1270+
1271+
end function get_relative_difference_real4
1272+
1273+
real(8) function get_relative_difference_real8(x, y, case)
1274+
1275+
real(8), intent(in) :: x
1276+
real(8), intent(in) :: y
1277+
integer, optional, intent(in) :: case
1278+
1279+
select case (merge(case, 1, present(case)))
1280+
1281+
case (1)
1282+
get_relative_difference_real8 = max(abs(x), abs(y))
1283+
1284+
case (2)
1285+
get_relative_difference_real8 = max(x, y)
1286+
1287+
case (3)
1288+
get_relative_difference_real8 = min(abs(x), abs(y))
1289+
1290+
case (4)
1291+
get_relative_difference_real8 = min(x, y)
1292+
1293+
case (5)
1294+
get_relative_difference_real8 = (x + y) / 2
1295+
1296+
case (6)
1297+
get_relative_difference_real8 = (abs(x) + abs(y)) / 2
1298+
1299+
end select
1300+
1301+
end function get_relative_difference_real8
12061302

12071303
end module assert_mod

0 commit comments

Comments
 (0)