FV3 Bundle
Compare_Float_Numbers.f90
Go to the documentation of this file.
1 !
2 ! Compare_Float_Numbers
3 !
4 ! Module containing routines to perform equality and relational
5 ! comparisons on floating point numbers.
6 !
7 !
8 ! CREATION HISTORY:
9 ! Written by: Paul van Delst, 01-Apr-2003
10 ! paul.vandelst@noaa.gov
11 !
12 
14 
15 
16  ! -----------------
17  ! Environment setup
18  ! -----------------
19  ! Module usage
20  USE type_kinds, ONLY: single, double
21  ! Disable all implicit typing
22  IMPLICIT NONE
23 
24 
25  ! ------------
26  ! Visibilities
27  ! ------------
28  PRIVATE
29  ! Parameters
30  PUBLIC :: default_n_sigfig
31  ! Operators
32  PUBLIC :: OPERATOR (.equalto.)
33  PUBLIC :: OPERATOR (.greaterthan.)
34  PUBLIC :: OPERATOR (.lessthan.)
35  ! Procedures
36  PUBLIC :: compare_float
37  PUBLIC :: tolerance
39 
40 
41  ! ---------------------
42  ! Procedure overloading
43  ! ---------------------
44 
45  INTERFACE compare_float
46  MODULE PROCEDURE compare_real_single
47  MODULE PROCEDURE compare_real_double
48  MODULE PROCEDURE compare_complex_single
49  MODULE PROCEDURE compare_complex_double
50  END INTERFACE compare_float
51 
52  INTERFACE OPERATOR (.equalto.)
53  MODULE PROCEDURE equalto_real_single
54  MODULE PROCEDURE equalto_real_double
55  MODULE PROCEDURE equalto_complex_single
56  MODULE PROCEDURE equalto_complex_double
57  END INTERFACE OPERATOR (.EqualTo.)
58 
59  INTERFACE OPERATOR (.greaterthan.)
60  MODULE PROCEDURE is_greater_than_single
61  MODULE PROCEDURE is_greater_than_double
62  END INTERFACE OPERATOR (.GreaterThan.)
63 
64  INTERFACE OPERATOR (.lessthan.)
65  MODULE PROCEDURE is_less_than_single
66  MODULE PROCEDURE is_less_than_double
67  END INTERFACE OPERATOR (.LessThan.)
68 
69  INTERFACE tolerance
70  MODULE PROCEDURE tolerance_real_single
71  MODULE PROCEDURE tolerance_real_double
72  MODULE PROCEDURE tolerance_complex_single
73  MODULE PROCEDURE tolerance_complex_double
74  END INTERFACE tolerance
75 
77  MODULE PROCEDURE cwt_real_single
78  MODULE PROCEDURE cwt_real_double
79  MODULE PROCEDURE cwt_complex_single
80  MODULE PROCEDURE cwt_complex_double
81  END INTERFACE compares_within_tolerance
82 
83  ! -----------------
84  ! Module parameters
85  ! -----------------
86  ! Module Version Id
87  CHARACTER(*), PARAMETER :: module_version_id = &
88  '$Id: Compare_Float_Numbers.f90 60152 2015-08-13 19:19:13Z paul.vandelst@noaa.gov $'
89  ! Numeric literals
90  REAL(Single), PARAMETER :: sp_zero = 0.0_single
91  REAL(Double), PARAMETER :: dp_zero = 0.0_double
92  REAL(Single), PARAMETER :: sp_one = 1.0_single
93  REAL(Double), PARAMETER :: dp_one = 1.0_double
94  REAL(Single), PARAMETER :: sp_ten = 10.0_single
95  REAL(Double), PARAMETER :: dp_ten = 10.0_double
96  REAL(Single), PARAMETER :: sp_hundred = 100.0_single
97  REAL(Double), PARAMETER :: dp_hundred = 100.0_double
98  REAL(Single), PARAMETER :: sp_compare_cutoff = 1.0e-15_single
99  REAL(Double), PARAMETER :: dp_compare_cutoff = 1.0e-15_double
100  ! Default number of significant figures
101  INTEGER, PARAMETER :: default_n_sigfig = 6
102 
103 
104 CONTAINS
105 
106 
107 !----------------------------------------------------------------------------------
108 !:sdoc+:
109 ! NAME:
110 ! .EqualTo.
111 !
112 ! PURPOSE:
113 ! Relational operator to test the equality of REAL operands.
114 !
115 ! CALLING SEQUENCE:
116 ! IF ( x .EqualTo. y ) THEN
117 ! .....
118 ! END IF
119 !
120 ! OPERANDS:
121 ! x, y: Two congruent floating point data objects to compare.
122 ! UNITS: N/A
123 ! TYPE: REAL(Single), REAL(Double)
124 ! COMPLEX(Single), COMPLEX(Double)
125 ! DIMENSION: Scalar, or any allowed rank array.
126 !
127 ! OPERATOR RESULT:
128 ! (x .EqualTo. y) The result is a logical value indicating whether
129 ! the operands are equal to within numerical precision
130 ! UNITS: N/A
131 ! TYPE: LOGICAL
132 ! DIMENSION: Same as operands.
133 !
134 ! PROCEDURE:
135 ! The test performed is
136 !
137 ! ABS( x - y ) < SPACING( MAX(ABS(x),ABS(y)) )
138 !
139 ! If the result is .TRUE., the numbers are considered equal. For complex
140 ! input the test is applied separately to the real and imaginary parts.
141 !:sdoc-:
142 !----------------------------------------------------------------------------------
143 
144  ELEMENTAL FUNCTION equalto_real_single( x, y ) RESULT( EqualTo )
145  REAL(Single), INTENT(IN) :: x, y
146  LOGICAL :: equalto
147  equalto = abs(x-y) < spacing( max(abs(x),abs(y)) )
148  END FUNCTION equalto_real_single
149 
150  ELEMENTAL FUNCTION equalto_real_double( x, y ) RESULT( EqualTo )
151  REAL(Double), INTENT(IN) :: x, y
152  LOGICAL :: equalto
153  equalto = abs(x-y) < spacing( max(abs(x),abs(y)) )
154  END FUNCTION equalto_real_double
155 
156  ELEMENTAL FUNCTION equalto_complex_single( x, y ) RESULT( EqualTo )
157  COMPLEX(Single), INTENT(IN) :: x, y
158  LOGICAL :: equalto
159  REAL(Single) :: rx, ix
160  REAL(Single) :: ry, iy
161  rx = REAL(x,single); ix = aimag(x)
162  ry = REAL(y,single); iy = aimag(y)
163  equalto = equalto_real_single( rx, ry ) .AND. equalto_real_single( ix, iy )
164  END FUNCTION equalto_complex_single
165 
166  ELEMENTAL FUNCTION equalto_complex_double( x, y ) RESULT( EqualTo )
167  COMPLEX(Double), INTENT(IN) :: x, y
168  LOGICAL :: equalto
169  REAL(Double) :: rx, ix
170  REAL(Double) :: ry, iy
171  rx = REAL(x,double); ix = aimag(x)
172  ry = REAL(y,double); iy = aimag(y)
173  equalto = equalto_real_double( rx, ry ) .AND. equalto_real_double( ix, iy )
174  END FUNCTION equalto_complex_double
175 
176 
177 !----------------------------------------------------------------------------------
178 !:sdoc+:
179 ! NAME:
180 ! .GreaterThan.
181 !
182 ! PURPOSE:
183 ! Relational operator to test if one REAL operand is greater than another.
184 !
185 ! CALLING SEQUENCE:
186 ! IF ( x .GreaterThan. y ) THEN
187 ! .....
188 ! END IF
189 !
190 ! OPERANDS:
191 ! x, y: Two congruent floating point data objects to compare.
192 ! UNITS: N/A
193 ! TYPE: REAL(Single) [ == default real]
194 ! OR
195 ! REAL(Double)
196 ! DIMENSION: Scalar, or any allowed rank array.
197 !
198 ! OPERATOR RESULT:
199 ! (x .GreaterThan. y) The result is a logical value indicating whether
200 ! the operand x is greater than y by more than
201 ! the spacing between representable floating point
202 ! numbers.
203 ! UNITS: N/A
204 ! TYPE: LOGICAL
205 ! DIMENSION: Same as operands.
206 !
207 ! PROCEDURE:
208 ! The test performed is
209 !
210 ! ( x - y ) >= SPACING( MAX(ABS(x),ABS(y)) )
211 !
212 ! If the result is .TRUE., x is considered greater than y.
213 !:sdoc-:
214 !----------------------------------------------------------------------------------
215 
216  ELEMENTAL FUNCTION is_greater_than_single( x, y ) RESULT ( Greater_Than )
217  REAL(Single), INTENT(IN) :: x, y
218  LOGICAL :: greater_than
219  IF ( (x-y) >= spacing( max( abs(x), abs(y) ) ) ) THEN
220  greater_than = .true.
221  ELSE
222  greater_than = .false.
223  END IF
224  END FUNCTION is_greater_than_single
225 
226 
227  ELEMENTAL FUNCTION is_greater_than_double( x, y ) RESULT ( Greater_Than )
228  REAL(Double), INTENT(IN) :: x, y
229  LOGICAL :: greater_than
230  IF ( (x-y) >= spacing( max( abs(x), abs(y) ) ) ) THEN
231  greater_than = .true.
232  ELSE
233  greater_than = .false.
234  END IF
235  END FUNCTION is_greater_than_double
236 
237 
238 !----------------------------------------------------------------------------------
239 !:sdoc+:
240 ! NAME:
241 ! .LessThan.
242 !
243 ! PURPOSE:
244 ! Relational operator to test if one REAL operand is less than another.
245 !
246 ! CALLING SEQUENCE:
247 ! IF ( x .LessThan. y ) THEN
248 ! .....
249 ! END IF
250 !
251 ! OPERANDS:
252 ! x, y: Two congruent floating point data objects to compare.
253 ! UNITS: N/A
254 ! TYPE: REAL(Single) [ == default real]
255 ! OR
256 ! REAL(Double)
257 ! DIMENSION: Scalar, or any allowed rank array.
258 !
259 ! OPERATOR RESULT:
260 ! (x .LessThan. y) The result is a logical value indicating whether
261 ! the operand x is less than y by more than the
262 ! spacing between representable floating point
263 ! numbers.
264 ! UNITS: N/A
265 ! TYPE: LOGICAL
266 ! DIMENSION: Same as operands.
267 !
268 ! PROCEDURE:
269 ! The test performed is
270 !
271 ! ( y - x ) >= SPACING( MAX(ABS(x),ABS(y)) )
272 !
273 ! If the result is .TRUE., x is considered less than y.
274 !:sdoc-:
275 !----------------------------------------------------------------------------------
276 
277  ELEMENTAL FUNCTION is_less_than_single( x, y ) RESULT ( Less_Than )
278  REAL(Single), INTENT(IN) :: x, y
279  LOGICAL :: less_than
280  IF ( (y-x) >= spacing( max( abs(x), abs(y) ) ) ) THEN
281  less_than = .true.
282  ELSE
283  less_than = .false.
284  END IF
285  END FUNCTION is_less_than_single
286 
287 
288  ELEMENTAL FUNCTION is_less_than_double( x, y ) RESULT ( Less_Than )
289  REAL(Double), INTENT(IN) :: x, y
290  LOGICAL :: less_than
291  IF ( (y-x) >= spacing( max( abs(x), abs(y) ) ) ) THEN
292  less_than = .true.
293  ELSE
294  less_than = .false.
295  END IF
296  END FUNCTION is_less_than_double
297 
298 
299 !----------------------------------------------------------------------------------
300 !:sdoc+:
301 ! NAME:
302 ! Compare_Float
303 !
304 ! PURPOSE:
305 ! Function to compare floating point scalars and arrays with adjustible
306 ! precision tolerance.
307 !
308 ! CALLING SEQUENCE:
309 ! Result = Compare_Float( x, y, & ! Input
310 ! ULP =ULP , & ! Optional input
311 ! Percent=Percent ) ! Optional input
312 !
313 ! INPUT ARGUMENTS:
314 ! x, y: Two congruent floating point data objects to compare.
315 ! UNITS: N/A
316 ! TYPE: REAL(Single) [ == default real]
317 ! OR
318 ! REAL(Double)
319 ! OR
320 ! COMPLEX(Single)
321 ! OR
322 ! COMPLEX(Double)
323 ! DIMENSION: Scalar, or any allowed rank array.
324 ! ATTRIBUTES: INTENT(IN)
325 !
326 ! OPTIONAL INPUT ARGUMENTS:
327 ! ULP: Unit of data precision. The acronym stands for "unit in
328 ! the last place," the smallest possible increment or decrement
329 ! that can be made using a machine's floating point arithmetic.
330 ! A 0.5 ulp maximum error is the best you could hope for, since
331 ! this corresponds to always rounding to the nearest representable
332 ! floating-point number. Value must be positive - if a negative
333 ! value is supplied, the absolute value is used.
334 ! If not specified, the default value is 1.
335 ! This argument is ignored if the Percent optioanl argument is specifed.
336 ! UNITS: N/A
337 ! TYPE: INTEGER
338 ! DIMENSION: Scalar
339 ! ATTRIBUTES: OPTIONAL, INTENT(IN)
340 !
341 ! Percent: Specify a percentage difference value to use in comparing
342 ! the numbers rather than testing within some numerical
343 ! limit. The ULP argument is ignored if this argument is
344 ! specified.
345 ! UNITS: N/A
346 ! TYPE: REAL(Single) for REAL(Single) or COMPLEX(Single) x,y
347 ! OR
348 ! REAL(Double) for REAL(Double) or COMPLEX(Double) x,y
349 ! DIMENSION: Scalar
350 ! ATTRIBUTES: OPTIONAL, INTENT(IN)
351 !
352 ! FUNCTION RESULT:
353 ! Result: The return value is a logical value indicating whether
354 ! the inputs are equal (to within the required precision)
355 ! .TRUE. - if the floating point numbers are equal to
356 ! within the specified tolerance.
357 ! .FALSE. - if the floating point numbers are different.
358 ! UNITS: N/A
359 ! TYPE: LOGICAL
360 ! DIMENSION: Scalar
361 !
362 ! PROCEDURE:
363 ! ULP Test
364 ! --------
365 ! The test performed is
366 !
367 ! ABS( x - y ) < ( ULP * SPACING( MAX(ABS(x),ABS(y)) ) )
368 !
369 ! If the result is .TRUE., the numbers are considered equal.
370 !
371 ! The intrinsic function SPACING(x) returns the absolute spacing of numbers
372 ! near the value of x,
373 !
374 ! { EXPONENT(x)-DIGITS(x)
375 ! { 2.0 for x /= 0
376 ! SPACING(x) = {
377 ! {
378 ! { TINY(x) for x == 0
379 !
380 ! The ULP optional argument scales the comparison.
381 !
382 ! James Van Buskirk and James Giles suggested this method for floating
383 ! point comparisons in the comp.lang.fortran newsgroup.
384 !
385 !
386 ! Percent Test
387 ! ------------
388 ! The test performed is
389 !
390 ! 100.0 * ABS((x-y)/x) < Percent
391 !
392 ! If the result is .TRUE., the numbers are considered equal.
393 !
394 !
395 ! For complex numbers, the same test is applied to both the real and
396 ! imaginary parts and each result is ANDed.
397 !:sdoc-:
398 !----------------------------------------------------------------------------------
399 
400  ELEMENTAL FUNCTION compare_real_single( x, y, ULP, Percent ) RESULT( Compare )
401  ! Arguments
402  REAL(Single), INTENT(IN) :: x
403  REAL(Single), INTENT(IN) :: y
404  INTEGER , OPTIONAL, INTENT(IN) :: ulp
405  REAL(Single), OPTIONAL, INTENT(IN) :: percent
406  ! Function result
407  LOGICAL :: compare
408  ! Local variables
409  LOGICAL :: ulp_test
410  REAL(Single) :: rel
411 
412  ! Set up
413  ! ------
414  ulp_test = .true.
415  IF ( PRESENT(ulp) ) THEN
416  rel = REAL(ABS(ULP), single)
417  ELSE
418  rel = sp_one
419  END IF
420  IF ( PRESENT(percent) ) THEN
421  ulp_test = .false.
422  ! Test for zero x (elementals can't be recursive)
423  IF ( abs(x) < ( spacing( max(abs(x),sp_zero) ) ) ) ulp_test = .true.
424  END IF
425 
426  ! Compare the numbers
427  ! -------------------
428  IF ( ulp_test ) THEN
429  compare = abs(x-y) < ( rel * spacing( max(abs(x),abs(y)) ) )
430  ELSE
431  compare = sp_hundred*abs((x-y)/x) < percent
432  END IF
433  END FUNCTION compare_real_single
434 
435 
436  ELEMENTAL FUNCTION compare_real_double( x, y, ULP, Percent ) RESULT( Compare )
437  ! Arguments
438  REAL(Double), INTENT(IN) :: x
439  REAL(Double), INTENT(IN) :: y
440  INTEGER , OPTIONAL, INTENT(IN) :: ulp
441  REAL(Double), OPTIONAL, INTENT(IN) :: percent
442  ! Function result
443  LOGICAL :: compare
444  ! Local variables
445  LOGICAL :: ulp_test
446  REAL(Double) :: rel
447 
448  ! Set up
449  ! ------
450  ulp_test = .true.
451  IF ( PRESENT(ulp) ) THEN
452  rel = REAL(ABS(ULP), double)
453  ELSE
454  rel = dp_one
455  END IF
456  IF ( PRESENT(percent) ) THEN
457  ulp_test = .false.
458  ! Test for zero x (elementals can't be recursive)
459  IF ( abs(x) < ( spacing( max(abs(x),dp_zero) ) ) ) ulp_test = .true.
460  END IF
461 
462  ! Compare the numbers
463  ! -------------------
464  IF ( ulp_test ) THEN
465  compare = abs(x-y) < ( rel * spacing( max(abs(x),abs(y)) ) )
466  ELSE
467  compare = dp_hundred*abs((x-y)/x) < percent
468  END IF
469  END FUNCTION compare_real_double
470 
471 
472  ELEMENTAL FUNCTION compare_complex_single( x, y, ULP, Percent ) RESULT( Compare )
473  ! Arguments
474  COMPLEX(Single), INTENT(IN) :: x
475  COMPLEX(Single), INTENT(IN) :: y
476  INTEGER , OPTIONAL, INTENT(IN) :: ulp
477  REAL(Single) , OPTIONAL, INTENT(IN) :: percent
478  ! Function result
479  LOGICAL :: compare
480  ! Local variables
481  REAL(Single) :: xr, xi
482  REAL(Single) :: yr, yi
483 
484  ! Separate real and complex parts
485  ! -------------------------------
486  xr=REAL(x,single); xi=aimag(x)
487  yr=REAL(y,single); yi=aimag(y)
488 
489  ! Compare each part separately
490  ! ----------------------------
491  compare = compare_real_single(xr,yr,ulp=ulp,percent=percent) .AND. &
492  compare_real_single(xi,yi,ulp=ulp,percent=percent)
493  END FUNCTION compare_complex_single
494 
495 
496  ELEMENTAL FUNCTION compare_complex_double( x, y, ULP, Percent ) RESULT( Compare )
497  ! Arguments
498  COMPLEX(Double), INTENT(IN) :: x
499  COMPLEX(Double), INTENT(IN) :: y
500  INTEGER , OPTIONAL, INTENT(IN) :: ulp
501  REAL(Double) , OPTIONAL, INTENT(IN) :: percent
502  ! Function result
503  LOGICAL :: compare
504  ! Local variables
505  REAL(Double) :: xr, xi
506  REAL(Double) :: yr, yi
507 
508  ! Separate real and complex parts
509  ! -------------------------------
510  xr=REAL(x,double); xi=aimag(x)
511  yr=REAL(y,double); yi=aimag(y)
512 
513  ! Compare each part separately
514  ! ----------------------------
515  compare = compare_real_double(xr,yr,ulp=ulp,percent=percent) .AND. &
516  compare_real_double(xi,yi,ulp=ulp,percent=percent)
517  END FUNCTION compare_complex_double
518 
519 
520 !----------------------------------------------------------------------------------
521 !:sdoc+:
522 ! NAME:
523 ! Tolerance
524 !
525 ! PURPOSE:
526 ! Elemental function to compute a tolerance value for a given input for a
527 ! specified number of significant figures.
528 !
529 ! CALLING SEQUENCE:
530 ! Result = Tolerance( x, n )
531 !
532 ! INPUT ARGUMENTS:
533 ! x: Floating point value for which a tolerance value is required.
534 ! UNITS: N/A
535 ! TYPE: REAL(Single) [ == default real]
536 ! OR
537 ! REAL(Double)
538 ! OR
539 ! COMPLEX(Single)
540 ! OR
541 ! COMPLEX(Double)
542 ! DIMENSION: Scalar or any rank array.
543 ! ATTRIBUTES: INTENT(IN)
544 !
545 ! n: The approximate number of significant figures for which the
546 ! tolerance is required.
547 ! UNITS: N/A
548 ! TYPE: INTEGER
549 ! DIMENSION: Scalar or same as input x.
550 ! ATTRIBUTES: INTENT(IN)
551 !
552 ! FUNCTION RESULT:
553 ! Result: The return value is a tolerance value that can be used to
554 ! compare two numbers.
555 ! UNITS: N/A
556 ! TYPE: Same as input x.
557 ! DIMENSION: Same as input x.
558 !:sdoc-:
559 !----------------------------------------------------------------------------------
560 
561  ELEMENTAL FUNCTION tolerance_real_single(x,n) RESULT( Tolerance )
562  REAL(Single), INTENT(IN) :: x
563  INTEGER , INTENT(IN) :: n
564  REAL(Single) :: tolerance
565  INTEGER :: e
566  IF (abs(x) > sp_zero) THEN
567  e = floor(log10(abs(x))) - n
568  tolerance = sp_ten**e
569  ELSE
570  tolerance = sp_one
571  END IF
572  END FUNCTION tolerance_real_single
573 
574  ELEMENTAL FUNCTION tolerance_real_double(x,n) RESULT( Tolerance )
575  REAL(Double), INTENT(IN) :: x
576  INTEGER, INTENT(IN) :: n
577  REAL(Double) :: tolerance
578  INTEGER :: e
579  IF (abs(x) > dp_zero) THEN
580  e = floor(log10(abs(x))) - n
581  tolerance = dp_ten**e
582  ELSE
583  tolerance = dp_one
584  END IF
585  END FUNCTION tolerance_real_double
586 
587  ELEMENTAL FUNCTION tolerance_complex_single(x,n) RESULT( Tolerance )
588  COMPLEX(Single), INTENT(IN) :: x
589  INTEGER, INTENT(IN) :: n
590  COMPLEX(Single) :: tolerance
591  REAL(Single) :: tr, ti
592  tr = tolerance_real_single(REAL(x,Single),n)
593  ti = tolerance_real_single(aimag(x),n)
594  tolerance = cmplx(tr,ti,single)
595  END FUNCTION tolerance_complex_single
596 
597  ELEMENTAL FUNCTION tolerance_complex_double(x,n) RESULT( Tolerance )
598  COMPLEX(Double), INTENT(IN) :: x
599  INTEGER, INTENT(IN) :: n
600  COMPLEX(Double) :: tolerance
601  REAL(Double) :: tr, ti
602  tr = tolerance_real_double(REAL(x,Double),n)
603  ti = tolerance_real_double(aimag(x),n)
604  tolerance = cmplx(tr,ti,double)
605  END FUNCTION tolerance_complex_double
606 
607 
608 !----------------------------------------------------------------------------------
609 !:sdoc+:
610 ! NAME:
611 ! Compares_Within_Tolerance
612 !
613 ! PURPOSE:
614 ! Elemental function to determine if two values are comparable withing
615 ! a given tolerance determined by the number of significant figures
616 ! used in the comparison.
617 !
618 ! CALLING SEQUENCE:
619 ! Result = Compare_Within_Tolerance( x, y, n, cutoff=cutoff )
620 !
621 ! INPUTS:
622 ! x, y: Floating point values to be compared.
623 ! UNITS: N/A
624 ! TYPE: REAL(Single) [ == default real]
625 ! OR
626 ! REAL(Double)
627 ! OR
628 ! COMPLEX(Single)
629 ! OR
630 ! COMPLEX(Double)
631 ! DIMENSION: Scalar or any rank array.
632 ! ATTRIBUTES: INTENT(IN)
633 !
634 ! n: The approximate number of significant figures for which the
635 ! tolerance is required.
636 ! UNITS: N/A
637 ! TYPE: INTEGER
638 ! DIMENSION: Scalar or same as input x, y.
639 ! ATTRIBUTES: INTENT(IN)
640 !
641 ! OPTIONAL INPUTS:
642 ! cutoff: Floating point value below which the comparison is not
643 ! performed. In this case, the function result will be .TRUE.
644 ! If not specified, the default value is 1.0e-15 for real
645 ! input, or (1.0e-15,1.0e-15) for complex input.
646 ! UNITS: N/A
647 ! TYPE: Same as input x
648 ! DIMENSION: Scalar or same as input x, y.
649 ! ATTRIBUTES: INTENT(IN), OPTIONAL
650 !
651 ! FUNCTION RESULT:
652 ! Result: The return value is a logical value indicating if the
653 ! comparison was successful or not.
654 ! If .TRUE. , the two numbers compare within the prescribed
655 ! tolerance, or
656 ! .FALSE., they do not.
657 ! UNITS: N/A
658 ! TYPE: LOGICAL
659 ! DIMENSION: Same as input x, y.
660 !:sdoc-:
661 !----------------------------------------------------------------------------------
662 
663  ELEMENTAL FUNCTION cwt_real_single(x,y,n,cutoff) RESULT(is_comparable)
664  REAL(Single), INTENT(IN) :: x, y
665  INTEGER, INTENT(IN) :: n
666  REAL(Single), OPTIONAL, INTENT(IN) :: cutoff
667  LOGICAL :: is_comparable
668  REAL(Single) :: c
669  IF ( PRESENT(cutoff) ) THEN
670  c = cutoff
671  ELSE
673  END IF
674  is_comparable = .true.
675  IF ( abs(x) > c .OR. abs(y) > c ) is_comparable = abs(x-y) < tolerance(x,n)
676  END FUNCTION cwt_real_single
677 
678 
679  ELEMENTAL FUNCTION cwt_real_double(x,y,n,cutoff) RESULT(is_comparable)
680  REAL(Double), INTENT(IN) :: x, y
681  INTEGER, INTENT(IN) :: n
682  REAL(Double), OPTIONAL, INTENT(IN) :: cutoff
683  LOGICAL :: is_comparable
684  REAL(Double) :: c
685  IF ( PRESENT(cutoff) ) THEN
686  c = cutoff
687  ELSE
689  END IF
690  is_comparable = .true.
691  IF ( abs(x) > c .OR. abs(y) > c ) is_comparable = abs(x-y) < tolerance(x,n)
692  END FUNCTION cwt_real_double
693 
694 
695  ELEMENTAL FUNCTION cwt_complex_single(x,y,n,cutoff) RESULT(is_comparable)
696  COMPLEX(Single), INTENT(IN) :: x, y
697  INTEGER, INTENT(IN) :: n
698  COMPLEX(Single), OPTIONAL, INTENT(IN) :: cutoff
699  LOGICAL :: is_comparable
700  COMPLEX(Single) :: c
701  IF ( PRESENT(cutoff) ) THEN
702  c = cutoff
703  ELSE
705  END IF
706  is_comparable = cwt_real_single(REAL(x,Single),REAL(y,Single),n,cutoff=real(c,single) ) .AND. &
707  cwt_real_single(aimag(x),aimag(y),n,cutoff=aimag(c))
708  END FUNCTION cwt_complex_single
709 
710 
711  ELEMENTAL FUNCTION cwt_complex_double(x,y,n,cutoff) RESULT(is_comparable)
712  COMPLEX(Double), INTENT(IN) :: x, y
713  INTEGER, INTENT(IN) :: n
714  COMPLEX(Double), OPTIONAL, INTENT(IN) :: cutoff
715  LOGICAL :: is_comparable
716  COMPLEX(Double) :: c
717  IF ( PRESENT(cutoff) ) THEN
718  c = cutoff
719  ELSE
721  END IF
722  is_comparable = cwt_real_double(REAL(x,Double),REAL(y,Double),n,cutoff=real(c,double) ) .AND. &
723  cwt_real_double(aimag(x),aimag(y),n,cutoff=aimag(c))
724  END FUNCTION cwt_complex_double
725 
726 END MODULE compare_float_numbers
elemental logical function cwt_complex_double(x, y, n, cutoff)
real(single), parameter sp_ten
elemental complex(single) function tolerance_complex_single(x, n)
elemental logical function compare_real_double(x, y, ULP, Percent)
elemental logical function is_greater_than_double(x, y)
real(double), parameter dp_compare_cutoff
elemental logical function equalto_real_double(x, y)
elemental logical function compare_complex_single(x, y, ULP, Percent)
integer, parameter, public double
Definition: Type_Kinds.f90:106
integer, parameter, public single
Definition: Type_Kinds.f90:105
elemental logical function compare_complex_double(x, y, ULP, Percent)
elemental logical function is_less_than_double(x, y)
elemental logical function is_greater_than_single(x, y)
real(double), parameter dp_zero
real(double), parameter dp_one
real(double), parameter dp_ten
elemental logical function is_less_than_single(x, y)
elemental real(double) function tolerance_real_double(x, n)
elemental logical function equalto_real_single(x, y)
character(*), parameter module_version_id
integer, parameter, public default_n_sigfig
elemental logical function cwt_real_single(x, y, n, cutoff)
real(single), parameter sp_compare_cutoff
elemental complex(double) function tolerance_complex_double(x, n)
elemental logical function compare_real_single(x, y, ULP, Percent)
#define max(a, b)
Definition: mosaic_util.h:33
elemental logical function cwt_complex_single(x, y, n, cutoff)
real(single), parameter sp_hundred
real(single), parameter sp_zero
elemental logical function equalto_complex_double(x, y)
real(single), parameter sp_one
real(double), parameter dp_hundred
elemental logical function cwt_real_double(x, y, n, cutoff)
elemental logical function equalto_complex_single(x, y)
elemental real(single) function tolerance_real_single(x, n)