 |
forums.silverfrost.com Welcome to the Silverfrost forums
|
View previous topic :: View next topic |
Author |
Message |
eric_carwardine
Joined: 13 Jun 2009 Posts: 70 Location: Perth, Western Australia
|
Posted: Sun May 08, 2011 6:20 pm Post subject: Comparing floating point quantities for inequality |
|
|
G'day, folks
What's a more reliable way of comparing floating point quantities for inequality? The ftn95 compiler reports that -
Code: |
if( rate .ne. 0.0 ) goto 300
|
may give misleading results.
Eric Carwardine, in Perth, Western Australia |
|
Back to top |
|
 |
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Sun May 08, 2011 6:29 pm Post subject: Re: Comparing floating point quantities for inequality |
|
|
eric_carwardine wrote: | G'day, folks
What's a more reliable way of comparing floating point quantities for inequality? The ftn95 compiler reports that -
Code: |
if( rate .ne. 0.0 ) goto 300
|
may 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).
Code: |
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:
Code: |
if (abs(rate) > 1.0e-8) then
! .. do something when rate not close to zero.
end if
|
|
|
Back to top |
|
 |
LitusSaxonicum
Joined: 23 Aug 2005 Posts: 2402 Location: Yateley, Hants, UK
|
Posted: Sun May 08, 2011 7:13 pm Post subject: |
|
|
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.
Code: | 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 (real*4 or real*8), 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:
Code: | 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 |
|
Back to top |
|
 |
JohnCampbell
Joined: 16 Feb 2006 Posts: 2615 Location: Sydney
|
Posted: Mon May 09, 2011 3:14 am Post subject: |
|
|
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.
1) The first, where I choose to ignore the error, such as when:
A = B
{do some calculations}
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.
2) Where the warning has some meaning, where you are testing the value of A and must recognise that real arithmetic has some finite accuracy. In this case you need to find an error "ACC" which is within limits of the calculation or within the accuracy of the method. Examples are:
1.0d-12 or 1.0e-6 may be realistic for real*8 or real*4, but also depend on the magnitude of A, as if A is expected to be 1.e-6, then a test for 1.e-16 may be more sensible for real*8 calculations.
In short it is difficult to apply a general rule for ACC.
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:
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 |
|
Back to top |
|
 |
Wilfried Linder
Joined: 14 Nov 2007 Posts: 314 Location: D�sseldorf, Germany
|
Posted: Mon May 09, 2011 9:08 am Post subject: |
|
|
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 |
|
Back to top |
|
 |
eric_carwardine
Joined: 13 Jun 2009 Posts: 70 Location: Perth, Western Australia
|
Posted: Wed Jun 01, 2011 2:21 pm Post subject: |
|
|
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 real*4 ... "
I must admit, Eddie, that Clearwin's boycotting of real*4 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 ...
Code: |
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 |
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|