G'day, folks 😃
What's a more reliable way of comparing floating point quantities for inequality? The ftn95 compiler reports that -
if( rate .ne. 0.0 ) goto 300
may give misleading results.
Eric Carwardine, in Perth, Western Australia
Welcome to our forums
G'day, folks 😃
What's a more reliable way of comparing floating point quantities for inequality? The ftn95 compiler reports that -
if( rate .ne. 0.0 ) goto 300
may give misleading results.
Eric Carwardine, in Perth, Western Australia
Quoted from eric_carwardine G'day, folks 😃
What's a more reliable way of comparing floating point quantities for inequality? The ftn95 compiler reports that -
if( rate .ne. 0.0 ) goto 300may give misleading results.
Eric Carwardine, in Perth, Western Australia
Good morning.
Its not usually a good idea to test for equality with floating point numbers (or inequality).
The compiler is just issuing a warning. You can turn the warning off in options or use tricks like the following (and hope the compiler doesn't spot what you are doing).
if (rate > 0.0 .or. rate < 0.0) then
! ... do something when rate /= 0.0
end if
However, the effect may still give answers you don't expect.
Conventional wisdom is to do something like the following:
if (abs(rate) > 1.0e-8) then
! .. do something when rate not close to zero.
end if
Hi Eric,
This warning often irritates me too, particularly as I try to catch divide-by-zeroes that are the result of wrong data input (normally it hasn't been done) and not a calculation I expect to produce a 'perfect' answer - I've known about roundoff for more than 4 decades, and already know that in some cases these tests aren't a good idea!
If you set a value in an assignment statement, or read a value in from a datafile, and the value is zero (or any other value for that matter), then it is perfectly proper to test for it.
e.g.
A = 0.0
IF (A .EQ. 0.0) THEN
You can turn off the warning for this with -ignore 179 on the command line for compilation.
The problem that FTN95 reports is that if the number is the result of a calculation, it will not be exactly calculated, and then you have to test within the range of roundoff. The accuracy you will get depends on the nature of the calculation, whether or not you use single or double precision (real4 or real8), how accurate the values were in the first instance, etc. If you are testing newly written code, then I advise not using the -ignore 179 option, and put up with the messages.
While programming with Clearwin I have just about given up on real*4. If find it useful to take the absolute value of the difference between two things, and compare that to the biggest difference I would consider meaningful:
IF (DABS(A-B) .GT. ACC) THEN ... (they are different)
(Of course, in Fortran 90/95, just ABS will do). As an example, if I am surveying, then 2 points less than 0.5mm apart are considered the same, so ACC = 0.5 if my units are mm, or 0.0005 if my units are m). This is better than you can achieve with real*4. The roundoff is often a lot bigger than the 'resolving power' of the datatype.
Eddie
Eric,
I have tried for a while to adopt an approach which limits the warnings that FTN95 provide. I have 2 cases where I adopt different approaches.
A = B
if (A == B) ... ! check if A has not changed
In this case B is a special value which I have used to previously apply to A ( B can also be 0 ). I am testing if A has changed in any way. In this case I ignore the warning. I've also asumed that 'zero' is a unique real number.
For Eddie's example IF (DABS(A-B) .GT. ACC) THEN A sensible approach to ACC could be ACC = ( Abs(A) + Abs(b) ) *1.d-8,
It all depends on how frequently you do the calculation and what is the consequence of getting the test wrong. In the case of avoiding divide by zero for IF (A.NE.B) is true and if A-B is very small, and 1 / (A-B) will be very large. You need to check the consequence, which is often not a problem.
Other problems come in when ACC is set to a rounded value, eg ACC = 0.1 . In this case 0.1_1 is different to 0.1_2 and this can cause some other problems. Try the following code:
real*8 x
real*4 b, c
!
x = 0.1_2
b = 0.1_1
!
c = b-x
write (*,*) x,b,c
end
The warning is useful to remind you to consider if it is a problem, but ignore in the case of my type 1.
John
Only as an additional remark: In some cases the tiny function may be helpful which gives the smallest positive number bigger than zero. This is really near to zero, so I usually take something like r = 10.D0*tiny(1.D0) and then the expression 'if (abs(x) .lt. r) ...'
Regards - Wilfried
G'day, folks 😃
Crikey, it's June already! I had intended getting back here much sooner. Many thanks for all the comments!
davidb wrote: ' ... and hope the compiler doesn't spot what you are doing ... ' Almost sounds like we're dealing with HAL, David, from the film '2001: A Space Odyssey' 😃 I wonder if the FTN95 compiler will ever pass the Turing Test?
Eddie wrote: ' ... While programming with Clearwin I have just about given up on real4 ... ' I must admit, Eddie, that Clearwin's boycotting of real4 caused me to frown a bit ... well, a lot. Then I wondered if I could get around it by using Fortran's 'internal write'. The essential code would be ...
character output*13
real*4 x
...
write(output, 11) x
11 format(g13.6)
ia=winio@('%`rs&', output)
... which is how I got my first demonstration of that very nice feature of Clearwin where it automatically updates any variable (such as 'output') that has been used in formatting the screen. Yes, very nice 😃
Thanks again, everybody who contributed. The overall effect of the total number of responses has lead me to ponder something I'm calling 'Anatomy of a calculation', which I'll present as a separate topic.
Eric