This is the mail archive of the cygwin mailing list for the Cygwin 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]

Re: strange bug in gettimeofday function


Thank you for your response.

>> But then I would like to know why comparison of two floating-point
>> numbers leads to different results: t0 is *exactly* the same as t1,
>> nevertheless the condition t0 > t1 is true (sometimes). That is the
>> question.
> 
> The multiplier 1e-6 cannot be represented exactly in binary floating
> point. Therefore the internal representation of your tv_usec will
> always be subject to rounding errors, maybe upwards or maybe
> downwards. Therefore, the result of this function will never be an
> accurate representation of the time as returned by struct timeval.
> The impact of the rounding error will depend on at what point the
> internal 80-bit value in the processor is rounded to 64 bits for
> storage as a double.
> 
> If you really must do this (and it is not advised) you might do
> better by multiplying tv_sec by 1e6 then adding tv_usec unscaled, so
> that the floating point variable holds an integer number of
> microseconds.
> 
> Also, if tv_sec is large, there might be significant loss of
> precision as tv_sec and tv_usec are shifted 6 decimal places (about
> 20 binary places) relative to each other in the mantissa.

Yes, that is. I just tried to reproduce a bug concerning gettimeofday,
and computing the time in such way was not my intension.

> 
> Floating point representation should never be used for something for
> which you need an accurate value, or where you require to test for
> two things being equal. You have a struct which conveys the time
> accurately: why not use that? It is trivial to write functions which
> compare two timevals for equality, or yield the difference between
> two timevals.
> 

The irony is that I usually give the same standard explanation about
floating-point to people who do not understand that :) *Unfortunately*,
you are right, and the difference really appears because the second
value returned by get_time being computed with full 80-bit precision
is kept in a fpu register during the comparison while the first value
is stored and then loaded as a 64-bit value. (Below here is the assembly
code explaining that.)

Nevertheless, you agree that if t0 > t1 then t0 - t1 cannot be exact
zero in *any* floating-point model, don't you? Even if optimization is
used, the compiler must not arbitrarily change the precision of the
same floating-point variable.


Andrew Makhorin

------------------------

How must not optimize:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

double get_time(void)
{     struct timeval tv;
      gettimeofday(&tv, NULL);
      return (double)tv.tv_sec + 1e-6 * (double)tv.tv_usec;
}

int main(void)
{       double t0 = get_time(), t1 = get_time();
        if (t0 > t1)
        {       int *t;
                printf("sizeof(double) = %d\n", sizeof(double));
                t = (int *)&t0;
                printf("t0 = %08X %08X\n", t[1], t[0]);
                t = (int *)&t1;
                printf("t1 = %08X %08X\n", t[1], t[0]);
                printf("t1 - t0 = %.20g \n", t1 - t0);
                exit(EXIT_FAILURE);
        }
        return 0;
}

  46 003e E8000000              call    __alloca
  46      00
  47 0043 E8000000              call    ___main
  47      00
  48 0048 E8B3FFFF              call    _get_time       ST(0) := result
  48      FF
  49 004d DD5DF8                fstpl   -8(%ebp)        t0 := ST(0) and pop
  50 0050 E8ABFFFF              call    _get_time       ST(0) := result
  50      FF
  51 0055 DD45F8                fldl    -8(%ebp)        push t0
  52 0058 D9C9                  fxch    %st(1)          ST(0) <-> ST(1)
  53 005a DD55F0                fstl    -16(%ebp)       t1 := ST(0)
  54 005d D9C9                  fxch    %st(1)          ST(0) <-> ST(1)
  55 005f DAE9                  fucompp                 ST(0) ? ST(1)
  56 0061 DFE0                  fnstsw  %ax             ax := status word
  57 0063 9E                    sahf
  58 0064 7704                  ja      L6
  59 0066 C9                    leave
  60 0067 31C0                  xorl    %eax, %eax
  61 0069 C3                    ret
  62                    L6:



--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


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