Optimization Bug in g77
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
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
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 >