Silverfrost Forums

Welcome to our forums

Logical Comparisons

24 Mar 2015 6:02 #15978

Have several situations where the FTN compiler warns about logical comparisons. Given the following statement: ALL VARIABLES A-H, O-Z ARE DECLARED DOUBLE PRECISION, THE VARIABLE IQUAVR IS INTEGER IQUAVR = 0 C IF (XMIDLH .NE. FMAP .AND. * XCOORD .LE. XMIDLH .AND * XMINTS .EQ. XMAXTS .AND. * YCOORD .GE. FLT0) IQUAVR = 1

THE LOGICAL RESULT IS THAT IQUAVR = 0, THE VARIABLES ARE ASSIGNED AS FOLLOWS: XMIDLH = 1.31750000 FMAP = .000000074 XCOORD= 1.31750000 XMINTS = 1.00000000 XMAXTS = 1.00000000 YCOORD = 1.0000000 FLT0 = 0.0000000 THE OBVIOUS SOLUTION SHOULD BE THAT IQUAVR = 1 AFTER THE COMPARISON BUT IT ACTUALLY RESULTS IN IQUAVR = 0 THE COMPILER WARNS ABOUT LOGICAL COMPARISON OF VARIABLES THAT THE RESULTS MAY BE UN-PREDICTABLE. HOWEVER, HOW DOES ONE GET AROUND THIS SITUATION TO GET THE CORRECT RESULT DESIRED. PLEASE ADVISE, SID KRAFT

24 Mar 2015 6:22 #15979

When comparing real numbers, I always use a tolerance factor. For example:

real:: numtol =1.e-12

if(x ⇐ y+numtol)then ...

With a statement such as this, and x =1.23456 and y =1.23456, the IF test above would produce the desired result, whereas the simpler statement,

if(x ⇐y) then ...

might fail because of roundoff or truncation errors in the floating point numbers.

24 Mar 2015 8:07 #15981

Sid,

If the numbers are input values, then the test should work, but it only takes one of them to be the result of a computation, and 'Kaboom'.

If you print out the logical result of each comparison, the 1 and 4 are definitely T but one of 2 or 3 is F.

Probably best to do a test for plus or minus, i.e.

IF (ABS(X-Y) .LE. NUMTOL) etc

Eddie

25 Mar 2015 1:49 #15983

Sid,

If the number you are using is not exact in binary representation, then you will have problems, as round-off will change the result, as in the following example:

     real*4    r1
     real*8    d1, d2, numtol
     integer*4 i

     do i = 1,2
!
     if (i==2) then
     r1 = 1.3175
     d1 = 1.3175d0
     d2 = 1.3175
     else
     r1 = 1.5
     d1 = 1.5d0
     d2 = 1.5
     end if
     write (*,*) 'Using d2=',d2
!
     if ( d1 == d2 ) write (*,*) 'd1 and d2 are the same'
     if ( d1 /= d2 ) write (*,*) 'd1 and d2 are different'
     write (*,*) d1-d2
!
     d2 = r1
     if ( d1 == d2 ) write (*,*) 'd1 and d2 are the same'
     if ( d1 /= d2 ) write (*,*) 'd1 and d2 are different'
     write (*,*) d1-d2
!
     d2 = d1
     if ( d1 == d2 ) write (*,*) 'd1 and d2 are the same'
     if ( d1 /= d2 ) write (*,*) 'd1 and d2 are different'
     write (*,*) d1-d2
     end do
!
     write (*,*) 'Estimation of accuracy of d1'
     numtol = abs (d1) * epsilon (d1)                         ! works if d1 /= 0

     write (*,*) 'number of digits in r1 =', precision (r1)
     write (*,*) 'epsilon for real*4     =', epsilon (r1)
     write (*,*) 'tiny    for real*4     =', tiny (r1)
     write (*,*) 'number of digits in d1 =', precision (d1)
     write (*,*) 'epsilon for real*8     =', epsilon (d1)
     write (*,*) 'tiny    for real*8     =', tiny (d1)
!
     write (*,*) 'accuracy of d1         =', numtol
     write (*,*) ' useful NUMTOL test    =', 2*numtol

end

However if you try r1 = 1.5 ; d1 = 1.5d0 ; d2 = 1.5 you will get a different result. The correct way is how Eddie suggests, although it is more to code and you need to know what precision to apply to (real*8) NUMTOL. Note: NUMTOL varies with the value of d1 (or d2 or the expected range of values for d1 or d2) if d1 is zero, then you need a different approach for NUMTOL. Tiny(d1) is the smallest number near (not) zero, so you can see for small values of d1 you need an even smaller value for NUMTOL.

Effectively you need to say; How close to d1 is the same value ?

There is another case, where you initially give d2 the value of d1, then at the end of your routine you ask if d2 has changed. In this case if ( d1/= d2) will give the answer you want (and the compiler warnings)

John

25 Mar 2015 9:04 #15986

John,

Perfect answer. My tolerances are often a lot more physical, e.g. for a distance in km or m, to within 1mm or 5mm!

Regards

Eddie

Please login to reply.