On 2004-04-27, at 12:32:29 +0100, Nicholas Clark wrote:

> On Mon, Apr 26, 2004 at 07:33:09AM +0200, Marcus Holland-Moritz wrote:
> 
> > Looking at the generated assembly code revealed that casting 'double'
> > to 'unsigned long long' calls __fixunsdfdi(). GCC implements this
> > function, as does OpenBSD's libc (!). Now, the cool thing is that
> > casting works as long as you do _not_ link libc to your executable.
> > I you do (and Perl does), you start getting wrong results for values
> > larger 2**32:
> 
> This rings bells. I'm sure we had the same issue with linking (not linking)
> libc with tracking down a modf bug on Linux once. But I can't find it in
> the archives.
> 
> How garbage is the output?

When casting floating point values > 2**31-1 (double or float)
to an unsigned long long, the result will be 1 too large.

> Can it be detected by Configure...

  $ uname -a
  OpenBSD openbsd34.mhxnet 3.4 GENERIC#18 i386
  $ cat test.c                                  
  typedef unsigned long long U64;
  
  int main(void)
  {
    double f = 4294967295.5;
    U64 u = (U64) f;
    return u != 4294967295ULL;
  }
  $ cc -o test test.c && ./test || echo bug     
  $ cc -o test -lc test.c && ./test || echo bug 
  bug

> ...and worked around?

I think so.

> Is it worth it?

Depends on how we want to work around. I see these options:

1) Forbid building with -Duse64bitint.

2) Look through the source for all code that casts floating point
   values to U64, and - if possible - work around the bug for
   values larger than 2**32-1.

3) Implement our own conversion routines... :-)

I'd vote for 1).

Marcus

> Nicholas Clark

-- 
Established technology tends to persist in the face of new technology.
                -- G. Blaauw, one of the designers of System 360

Reply via email to