Optimization Bug in g77

2004-10-23 Thread Steven E. Williamson
I have run into a strange problem with g77 when run with the -O or -O1
option but NOT with -O2, -O3, or no optimization.  Below is piece
of Fortran code (removed from a larger program) which illustrates the
problem.  The basic function of the code is to go through a list
of data (the RAW array) and accumulate an average and uncertainty
in the average, excluding "outlier points".  This is done iteratively
by calculating an average and standard deviation using only points
that differ by less than some number (NSIG) of standard deviations
from the average calculated by the previous iteration (in the first
iteration all points are accumulated).  The iteration is repeted until
the average does not change between two iterations or until some
maximum number of iterations is reached.  In the program below, some
fake data is first generated.  For technical reasons, the number of
"rejected points" and the number of iterations (normally integers) are
accumulated in double precision reals.

The problem with this code is that when compiled with either the -O or -O1
options, the maximum number of iterations is performed.  When compiled
with -O2, -O3, or no optimization options, only 2 iterations are done.
Some how the check for the averages of two successive iterations is
being disabled when -O or -O1 is selected.

Two other symptoms that I have noticed: if the -ffloat-store option is
used, then the program always works correctly (does only 2 iterations).
And, if the write statement immediately preceding the check for
equal averages is un-commented, the program also works correctly.

---Program optimization-test.F CUT HERE--
C   This program produces two different results depending on
C   the g77 optimization.
IMPLICIT NONE
C   Maximum number of iterations of the filtering process
INTEGER NITRMX
PARAMETER (NITRMX = 50)
C   Number of SIGMA outside of which data is rejected.
INTEGER NSIG
PARAMETER (NSIG = 40)
C   Number of data points
INTEGER NDAT
PARAMETER (NDAT = 200)
C
INTEGER I
REAL RAW(200)
DOUBLE PRECISION AV,SD,AVOLD,SDOLD,FIL(2),SUM,SUM2
C
FIL(2) = 1.D0
SDOLD = 1.D37
AVOLD = 0.D0
C   Generate some fake data (Gaussian tail with flat-top)
DO 100 I = 1,NDAT
RAW(I) = EXP(-((I-100.)/10.)**2)
100 CONTINUE
DO 110 I = NDAT/2-20,NDAT/2+20
RAW(I) = 1
110 CONTINUE
C
C   Scan data to calculate mean and uncertainty.  Reject
C   any data that is NSIG SIGMA from the mean (unless this
C   is the first iteration).
10  SUM = 0.D0
SUM2 = 0.D0
FIL(1) = 0.D0
DO 70 I = 1,NDAT
IF (FIL(2).LE.1.D0.OR.ABS(RAW(I)-AVOLD).LE.NSIG*SDOLD) THEN
SUM = SUM+RAW(I)
SUM2 = SUM2+RAW(I)**2
ELSE
FIL(1) = FIL(1)+1.D0
ENDIF
70  CONTINUE
C   Calculate a new mean and SIGMA.
AV = SUM/(NDAT-FIL(1))
C   This is the standard deviation of the mean (which is not the
C   same as the standard deviation of the measurement distribution,
C   i.e. the sample standard deviation.).
SD = SQRT(SUM2/(NDAT-FIL(1))-AV**2)/SQRT(NDAT-1-FIL(1))
c   write (6,*) av
IF (FIL(2).LE.1.D0.OR.AV.NE.AVOLD) THEN
IF (FIL(2).LT.NITRMX) THEN
C   If this is the first iteration, or if the process
C   hasn't converged, go back and re-scan.
FIL(2) = FIL(2)+1.D0
AVOLD = AV
SDOLD = SD
GO TO 10
ENDIF
ENDIF
write (6,*) fil(2),av,fil(1)
if (fil(2).eq.nitrmx) then
write (6,*) 'Wrong answer!'
else
write (6,*) 'Right answer.'
endif
STOP 'All done.'
END


Here is the Makefile that I use to genererate the executable of the
above program.  It assumes that the above Fortran is in a file
called optimization-test.F.  A number of different choices for
the FFLAGS (most commented out) are divided into a group that doesn't
work and a group that works.

---Makefile CUT HERE
# This is a make file for optimization-test.  The following commands are
# defined:
# make  Create program on source directory (don't install
#   in destination)
# make all  "
# make program  "
# make cleanRemove object files from the source directory
# make install  Move the program from the source directory to the
#   destination
# make update   Combines program creation with installation in
#   destination directory

# Final result of this make file
PROGRAM=optimization-test

OBJS=optimization-test.o

# Source file names 

Optimization Bug in g77

2004-10-26 Thread Steven E. Williamson
I have run into a strange problem with g77 when run with the -O or -O1
option but NOT with -O2, -O3, or no optimization.  Below is piece
of Fortran code (removed from a larger program) which illustrates the
problem.  The basic function of the code is to go through a list
of data (the RAW array) and accumulate an average and uncertainty
in the average, excluding "outlier points".  This is done iteratively
by calculating an average and standard deviation using only points
that differ by less than some number (NSIG) of standard deviations
from the average calculated by the previous iteration (in the first
iteration all points are accumulated).  The iteration is repeted until
the average does not change between two iterations or until some
maximum number of iterations is reached.  In the program below, some
fake data is first generated.  For technical reasons, the number of
"rejected points" and the number of iterations (normally integers) are
accumulated in double precision reals.

The problem with this code is that when compiled with either the -O or -O1
options, the maximum number of iterations is performed.  When compiled
with -O2, -O3, or no optimization options, only 2 iterations are done.
Some how the check for the averages of two successive iterations is
being disabled when -O or -O1 is selected.

Two other symptoms that I have noticed: if the -ffloat-store option is
used, then the program always works correctly (does only 2 iterations).
And, if the write statement immediately preceding the check for
equal averages is un-commented, the program also works correctly.

---Program optimization-test.F CUT HERE--
C   This program produces two different results depending on
C   the g77 optimization.
IMPLICIT NONE
C   Maximum number of iterations of the filtering process
INTEGER NITRMX
PARAMETER (NITRMX = 50)
C   Number of SIGMA outside of which data is rejected.
INTEGER NSIG
PARAMETER (NSIG = 40)
C   Number of data points
INTEGER NDAT
PARAMETER (NDAT = 200)
C
INTEGER I
REAL RAW(200)
DOUBLE PRECISION AV,SD,AVOLD,SDOLD,FIL(2),SUM,SUM2
C
FIL(2) = 1.D0
SDOLD = 1.D37
AVOLD = 0.D0
C   Generate some fake data (Gaussian tail with flat-top)
DO 100 I = 1,NDAT
RAW(I) = EXP(-((I-100.)/10.)**2)
100 CONTINUE
DO 110 I = NDAT/2-20,NDAT/2+20
RAW(I) = 1
110 CONTINUE
C
C   Scan data to calculate mean and uncertainty.  Reject
C   any data that is NSIG SIGMA from the mean (unless this
C   is the first iteration).
10  SUM = 0.D0
SUM2 = 0.D0
FIL(1) = 0.D0
DO 70 I = 1,NDAT
IF (FIL(2).LE.1.D0.OR.ABS(RAW(I)-AVOLD).LE.NSIG*SDOLD) THEN
SUM = SUM+RAW(I)
SUM2 = SUM2+RAW(I)**2
ELSE
FIL(1) = FIL(1)+1.D0
ENDIF
70  CONTINUE
C   Calculate a new mean and SIGMA.
AV = SUM/(NDAT-FIL(1))
C   This is the standard deviation of the mean (which is not the
C   same as the standard deviation of the measurement distribution,
C   i.e. the sample standard deviation.).
SD = SQRT(SUM2/(NDAT-FIL(1))-AV**2)/SQRT(NDAT-1-FIL(1))
c   write (6,*) av
IF (FIL(2).LE.1.D0.OR.AV.NE.AVOLD) THEN
IF (FIL(2).LT.NITRMX) THEN
C   If this is the first iteration, or if the process
C   hasn't converged, go back and re-scan.
FIL(2) = FIL(2)+1.D0
AVOLD = AV
SDOLD = SD
GO TO 10
ENDIF
ENDIF
write (6,*) fil(2),av,fil(1)
if (fil(2).eq.nitrmx) then
write (6,*) 'Wrong answer!'
else
write (6,*) 'Right answer.'
endif
STOP 'All done.'
END


Here is the Makefile that I use to genererate the executable of the
above program.  It assumes that the above Fortran is in a file
called optimization-test.F.  A number of different choices for
the FFLAGS (most commented out) are divided into a group that doesn't
work and a group that works.

---Makefile CUT HERE
# This is a make file for optimization-test.  The following commands are
# defined:
# make  Create program on source directory (don't install
#   in destination)
# make all  "
# make program  "
# make cleanRemove object files from the source directory
# make install  Move the program from the source directory to the
#   destination
# make update   Combines program creation with installation in
#   destination directory

# Final result of this make file
PROGRAM=optimization-test

OBJS=optimization-test.o

# Source file names 

Re: Optimization Bug in g77

2004-10-26 Thread Steven E. Williamson
Thanks for the quick response.  I have altered my code so that it
does not depend on the way extended precision is handled.  It
gives the right answer no mater how it is compiled.

I guess the moral is: don't try to check for exact equality between two
double precision numbers that have been calculated because one
may be in memory and the other may be stored with extra precision
in registers (in which case they will never come out equal).  Is
that a fair way to understand the behavior of g77/gcc/the CPU/the FPU?

Steve

On Tue, 26 Oct 2004, Andrew Pinski wrote:

> 
> On Oct 26, 2004, at 3:01 PM, Steven E. Williamson wrote:
> 
> > Two other symptoms that I have noticed: if the -ffloat-store option is
> > used, then the program always works correctly (does only 2 iterations).
> > And, if the write statement immediately preceding the check for
> > equal averages is un-commented, the program also works correctly.
> 
> There you said how to fix your problem -ffloat-store.  The point is that
> gcc (and g77) is using the additional precision which you are not 
> expecting
> to be used.  I am going to assume you are on x86 where this problem 
> comes
> up all the time.
> 
> Thanks,
> Andrew Pinski
>