Bug 23195 - [4.0 Regression] Using frexp with fabs produces negative result
Summary: [4.0 Regression] Using frexp with fabs produces negative result
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.0.1
: P2 critical
Target Milestone: 4.0.2
Assignee: Richard Biener
URL: http://gcc.gnu.org/ml/gcc-patches/200...
Keywords: monitored, patch, wrong-code
Depends on:
Blocks:
 
Reported: 2005-08-02 10:52 UTC by Mark Broadbent
Modified: 2005-11-14 13:56 UTC (History)
2 users (show)

See Also:
Host: i686-gnu-linux
Target: i686-gnu-linux
Build: i686-gnu-linux
Known to work: 3.4.0 4.1.0
Known to fail: 4.0.0 4.0.1
Last reconfirmed: 2005-08-02 11:54:14


Attachments
Example C++ code (177 bytes, text/plain)
2005-08-02 10:53 UTC, Mark Broadbent
Details
Preprocessor output from gcc 4.0.1 from testcase (9.07 KB, text/plain)
2005-08-02 10:53 UTC, Mark Broadbent
Details
Assembler output from g++ 4.0.1 from testcase (594 bytes, text/plain)
2005-08-02 10:54 UTC, Mark Broadbent
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Broadbent 2005-08-02 10:52:07 UTC
When frexp is used within a fabs function (as shown below) the value returned is
negative.

double a = fabs(frexp(b, &i));

Example code and temp files are attached.  This code works in gcc version 3.4
Comment 1 Mark Broadbent 2005-08-02 10:53:07 UTC
Created attachment 9407 [details]
Example C++ code
Comment 2 Mark Broadbent 2005-08-02 10:53:52 UTC
Created attachment 9408 [details]
Preprocessor output from gcc 4.0.1 from testcase
Comment 3 Mark Broadbent 2005-08-02 10:54:29 UTC
Created attachment 9409 [details]
Assembler output from g++ 4.0.1 from testcase
Comment 4 Mark Broadbent 2005-08-02 10:56:59 UTC
Output from test program

mbroadbent@panther:~$ g++-4.0 -o test_frexp test_frexp.cpp -save-temps -lm
mbroadbent@panther:~$ ./test_frexp
q: -123.456 a: -0.9645 e: 7
q: -123.456 a: 0.9645 b: -0.9645 e: 7
Comment 5 Volker Reichelt 2005-08-02 11:54:14 UTC
Confirmed. Ouch!
Comment 6 Richard Biener 2005-08-02 12:07:42 UTC
Well... 

int
tree_expr_nonnegative_p (tree t)
{
...
           CASE_BUILTIN_F (BUILT_IN_FREXP)
...
             /* Always true.  */
              return 1;

Which the manpage of frexp seems to support:

DESCRIPTION
       The frexp() function is used to split the number x  into  a  normalized
       fraction and an exponent which is stored in exp.

RETURN VALUE
       The  frexp() function returns the normalized fraction.  If the argument
       x is not zero, the normalized fraction is x times a power of  two,  and
       is always in the range 1/2 (inclusive) to 1 (exclusive).  If x is zero,
       then the normalized fraction is zero and zero is stored in exp.


so, we just fold away the fabs.  Your libm is broken.  And:

src/tests> ./test_frexp
q: -123.456 a: 0.9645 e: 7
q: -123.456 a: 0.9645 b: -0.9645 e: 7

though why b is negative here, contradicting the manpage, is unclear to me.
Comment 7 Richard Biener 2005-08-02 12:13:53 UTC
A safe fix would be to make tree_expr_nonnegative_p say don't-know for frexp.
Comment 8 Volker Reichelt 2005-08-02 12:30:42 UTC
I don't think that libm is broken. I think the man page is just inaccurate.
I just tried on IRIX and they also return negative results for a negative
argument.

> DESCRIPTION
>        The frexp() function is used to split the number x  into  a  normalized
>        fraction and an exponent which is stored in exp.

From this I'd expext that if I put the result and the exponent back together
I'll end up with the original number (that's my interpretation of "split").

> RETURN VALUE
>        The  frexp() function returns the normalized fraction.  If the argument
>        x is not zero, the normalized fraction is x times a power of  two,  and
>        is always in the range 1/2 (inclusive) to 1 (exclusive).  If x is zero,
>        then the normalized fraction is zero and zero is stored in exp.

However this section doesn't talk about the sign. The normalized part is
positive here, contradicting the stuff above. So I think that the man page
is just inaccurate.

I think the right fix is to move "CASE_BUILTIN_F (BUILT_IN_FREXP)"
into the following section:

	      /* True if the 1st argument is nonnegative.  */
	      return tree_expr_nonnegative_p (TREE_VALUE (arglist));
Comment 9 Volker Reichelt 2005-08-02 12:34:34 UTC
Here's a snippet from the manpage from hpux (as found on
http://www.informatik.uni-frankfurt.de/doc/man/hpux/frexp.3c.html )
which supports my claim from comment #8:

 NAME
      frexp(), ldexp(), modf() - split floating-point into mantissa and
      exponent

 SYNOPSIS
 DESCRIPTION
      Every non-zero number can be written uniquely as x*(2**n) where the
      ``mantissa'' (fraction) x is in the range 0.5 _ |x| < 1.0, and the
      ``exponent'' n is an integer.

      frexp()        returns the mantissa of a double value, and stores the
                     exponent indirectly in the location pointed to by eptr.
                     If value is zero, both results returned by frexp are
                     zero.

      ldexp()        returns the quantity value*(2**exp).

      modf()         returns the signed fractional part of value and stores
                     the integral part indirectly in the location pointed to
                     by iptr.
Comment 10 Andreas Schwab 2005-08-02 13:06:06 UTC
The C standard says: 
 
  [...], the frexp functions return the value x, such that x has a magnitude 
  in the interval [1/2, 1) or zero, and value equals x × 2^*exp. 
 
The magnitude is also known as the absolute value. 
Comment 11 Volker Reichelt 2005-08-02 13:10:49 UTC
I'll take care of this one.

Could anybody bug the maintainers of the manpages in the Linux Programmer's
manual (hpux, IRIX, Openbsd seem to have correct man pages).
Comment 12 Volker Reichelt 2005-08-02 13:13:33 UTC
Reassigning since Richard Guenther already posted a patch.
Comment 13 Andrew Pinski 2005-08-02 15:54:45 UTC
Fixed on the mainline.
Comment 14 Richard Biener 2005-08-02 15:58:50 UTC
Fixed.
Comment 15 Gabriel Dos Reis 2005-08-02 18:07:44 UTC
Subject: Re:  [4.0/4.1 Regression] Using frexp with fabs produces negative result

"reichelt at gcc dot gnu dot org" <gcc-bugzilla@gcc.gnu.org> writes:

| Here's a snippet from the manpage from hpux (as found on
| http://www.informatik.uni-frankfurt.de/doc/man/hpux/frexp.3c.html )
| which supports my claim from comment #8:

Why debate over manpages when the C standard describes the semantics?

-- Gaby
Comment 16 Volker Reichelt 2005-11-14 13:56:46 UTC
For the record:
I contacted the maintainer of the Linux man pages about the inaccurate
description of frexp (see comment #6). A corrected version will be in
man-pages-2.14.