When frexp is used within a fabs function (as shown below) the value returned is
double a = fabs(frexp(b, &i));
Example code and temp files are attached. This code works in gcc version 3.4
Created attachment 9407 [details]
Example C++ code
Created attachment 9408 [details]
Preprocessor output from gcc 4.0.1 from testcase
Created attachment 9409 [details]
Assembler output from g++ 4.0.1 from testcase
Output from test program
mbroadbent@panther:~$ g++-4.0 -o test_frexp test_frexp.cpp -save-temps -lm
q: -123.456 a: -0.9645 e: 7
q: -123.456 a: 0.9645 b: -0.9645 e: 7
tree_expr_nonnegative_p (tree t)
/* Always true. */
Which the manpage of frexp seems to support:
The frexp() function is used to split the number x into a normalized
fraction and an exponent which is stored in exp.
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:
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.
A safe fix would be to make tree_expr_nonnegative_p say don't-know for frexp.
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
> 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));
Here's a snippet from the manpage from hpux (as found on
which supports my claim from comment #8:
frexp(), ldexp(), modf() - split floating-point into mantissa and
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
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
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.
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).
Reassigning since Richard Guenther already posted a patch.
Fixed on the mainline.
Subject: Re: [4.0/4.1 Regression] Using frexp with fabs produces negative result
"reichelt at gcc dot gnu dot org" <firstname.lastname@example.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?
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