This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug testsuite/32057] Random failure on gfortran.dg/secnds.f



------- Comment #4 from dominiq at lps dot ens dot fr  2007-05-29 20:25 -------
Following the Steve Kargl's suggestion in

http://gcc.gnu.org/ml/gcc-patches/2007-05/msg01945.html

I have done the following test:

[archimede] test/fortran> cat > sec_prec_1.f90
implicit none
integer j, k, l, m, n
integer i, ifa, ifb, ifc
real a, b, c
i = 0 ; ifa = 0 ; ifb = 0 ; ifc = 0
do m = 0, 23
   do l = 0, 59
      do k = 0, 59
         do j = 0, 999
             i = i + 1
             a = 3600.0*real(m)+ 60.0*real(l) + real(k) + 0.001*real(j)
             b = 0.001*real(j) + real(k) + 60.0*real(l) + 3600.0*real(m)
             c = (3600000*m + 60000*l + 1000*k + j)/1000.0
             if (b /= c) ifa = ifa + 1
             if (a /= c) ifb = ifb + 1
             if (a /= b) ifc = ifc + 1
         end do
      end do
   end do
end do
print *, i, ifa, ifb, ifc
end

On PPC OSX and AMD64 Linux (with and without -O), I get:

    86400000    19312016    17523130     2683738

It seems hard to decide what is the right solution, expect that the same has to
be used in the test cases. On a Pentium Linux, I get the same result if I use
-ffloat-store. Without this flag I get:

    86400000        1934        1934           0

without -O and

    86400000    86313600    86313600           0

with -O.  Since I understand that in the later cases, the right hand side is
computed as real(10), hence a and b are the same after rounding to real(4).
However I don't see why the optimization has such a dramatic effect.

I have also run the following test:

[archimede] test/fortran> cat > sec_prec.f90
integer i, j, k, l, m, n
real a, b, c
k = 59
l = 59
m = 23
do i = 0, 9
   a = 86399.0 + 0.001*real(990+i)
   b = 0.001*real(990+i) + real(k) + 60.0*real(l) + 3600.0*real(m)
   c = (86399990 + i)/1000.0
   print '(I3,3(1PG20.10))', i, a, b, c
end do
end

which gives:

  0     86399.99219         86399.99219         86399.99219    
  1     86399.99219         86399.99219         86399.99219    
  2     86399.99219         86399.99219         86399.99219    
  3     86399.99219         86399.99219         86399.99219    
  4     86399.99219         86399.99219         86399.99219    
  5     86399.99219         86399.99219         86399.99219    
  6     86399.99219         86400.00000         86400.00000    
  7     86400.00000         86400.00000         86400.00000    
  8     86400.00000         86400.00000         86400.00000    
  9     86400.00000         86400.00000         86400.00000    

i.e., the last 3/4 ms gives 86400.0, hence the result of secnds(0.0) is inside
the interval [0.0,86400.0] and not inside [0.0,86400.0[ as I naively expected.
This is the cryptic point (2) in my comment #1.

A side effect is that if your are within this time frame and do

t1=secnds(0.0); t2=secnds(t1)

you get 86400.0 instead of 0.0. A possible solution is to add a
t1=min(86399.996,t1) to force the output in the semiopen interval.  With the
reversal of the time computation and putting everything in float, it leads to
the following patch:

--- gcc-4.3-20070525/libgfortran/intrinsics/date_and_time.c     Fri Apr  6
18:47:23 2007
+++ gcc-4.3-20070526/libgfortran/intrinsics/date_and_time.c     Mon May 28
21:40:46 2007
@@ -341,12 +341,15 @@

   free_mem (avalues);

-  temp1 = 3600.0 * (GFC_REAL_4)values[4] +
-           60.0 * (GFC_REAL_4)values[5] +
-                  (GFC_REAL_4)values[6] +
-          0.001 * (GFC_REAL_4)values[7];
-  temp2 = fmod (*x, 86400.0);
-  temp2 = (temp1 - temp2 >= 0.0) ? temp2 : (temp2 - 86400.0);
+  temp1 =  0.001f * (GFC_REAL_4)values[7] +
+                   (GFC_REAL_4)values[6] +
+           60.0f * (GFC_REAL_4)values[5] +
+         3600.0f * (GFC_REAL_4)values[4];
+          
+  /* Fix the round-off errors for the 3ms before midnight. */
+  temp1= (86399.996f>=temp1)? temp1 : 86399.996f;
+  temp2 = fmod (*x, 86400.0f);
+  temp2 = (temp1 - temp2 >= 0.0f) ? temp2 : (temp2 - 86400.0f);
   return temp1 - temp2;
 }

I have implemented part of it (without the reversal for temp1) on my last build
on OSX and it seems to work. For the other platforms I rely on binaries, so I
need some outside help to test the patch on them!-)


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32057


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]