@@ -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
6371contains
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
12071303end module assert_mod
0 commit comments