public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* A g++ bug ... or not ?
@ 2018-09-07 14:27 sisyphus1
  2018-09-07 15:03 ` Marc Glisse
  0 siblings, 1 reply; 7+ messages in thread
From: sisyphus1 @ 2018-09-07 14:27 UTC (permalink / raw)
  To: gcc-help

Hi,

The demo program:

/****/
/* try.c */
#include <stdio.h>
#include <math.h>

int main(void) {

  int x = -1074;

  printf("%e\n", pow (2.0, (double)x));
  printf("%e\n", pow (2.0, x));

  return 0;
}

/****/

If I build that program (using g++ version 7.3.0) with "g++ -ansi -o try 
try.c" I get output of:

4.940656e-324
0.000000e+000

whereas I expected output to be:

4.940656e-324
4.940656e-324

I guess that means that either my expectation is buggy, or something else is 
buggy.

Note 1:
If the "-ansi" switch is omitted, then the output matches my expectation.

Note 2:
If cmath is #included instead of math.h, then the output matches my 
expectation.

Note 3:
I believe (unproven) that if I use version 5.x.x (or earlier) of g++ then 
the output matches my expectation - otherwise it produces the unexpected 
output.

In a nutshell, I'm just trying to ascertain whether or not I should submit a 
bugzilla report about this.

Cheers,
Rob 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: A g++ bug ... or not ?
  2018-09-07 14:27 A g++ bug ... or not ? sisyphus1
@ 2018-09-07 15:03 ` Marc Glisse
  2018-09-07 15:43   ` Xi Ruoyao
  0 siblings, 1 reply; 7+ messages in thread
From: Marc Glisse @ 2018-09-07 15:03 UTC (permalink / raw)
  To: sisyphus1; +Cc: gcc-help

On Sat, 8 Sep 2018, sisyphus1@optusnet.com.au wrote:

> Hi,
>
> The demo program:
>
> /****/
> /* try.c */
> #include <stdio.h>
> #include <math.h>
>
> int main(void) {
>
> int x = -1074;
>
> printf("%e\n", pow (2.0, (double)x));
> printf("%e\n", pow (2.0, x));
>
> return 0;
> }
>
> /****/
>
> If I build that program (using g++ version 7.3.0) with "g++ -ansi -o try 
> try.c" I get output of:
>
> 4.940656e-324
> 0.000000e+000
>
> whereas I expected output to be:
>
> 4.940656e-324
> 4.940656e-324
>
> I guess that means that either my expectation is buggy, or something else is 
> buggy.
>
> Note 1:
> If the "-ansi" switch is omitted, then the output matches my expectation.

Don't use -ansi, use -std= . Most likely you did not mean to use 
-std=c++98.

The exact set of overloads of pow in the C++ standard has varied with 
time, https://en.cppreference.com/w/cpp/numeric/math/pow gives some idea.

> Note 2:
> If cmath is #included instead of math.h, then the output matches my
> expectation.

If you include cmath and not math.h, you should use std::pow.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: A g++ bug ... or not ?
  2018-09-07 15:03 ` Marc Glisse
@ 2018-09-07 15:43   ` Xi Ruoyao
  2018-09-07 22:48     ` Jonathan Wakely
  2018-09-08  1:58     ` sisyphus1
  0 siblings, 2 replies; 7+ messages in thread
From: Xi Ruoyao @ 2018-09-07 15:43 UTC (permalink / raw)
  To: sisyphus1; +Cc: gcc-help, Jonathan Wakely

On 2018-09-07 17:03 +0200, Marc Glisse wrote:
> On Sat, 8 Sep 2018, sisyphus1@optusnet.com.au wrote:
> 
> > Hi,
> > 
> > The demo program:
> > 
> > /****/
> > /* try.c */
> > #include <stdio.h>
> > #include <math.h>
> > 
> > int main(void) {
> > 
> > int x = -1074;
> > 
> > printf("%e\n", pow (2.0, (double)x));
> > printf("%e\n", pow (2.0, x));
> > 
> > return 0;
> > }
> > 
> > /****/
> > 
> > If I build that program (using g++ version 7.3.0) with "g++ -ansi -o try 
> > try.c" I get output of:
> > 
> > 4.940656e-324
> > 0.000000e+000
> > 
> > whereas I expected output to be:
> > 
> > 4.940656e-324
> > 4.940656e-324
> > 
> > I guess that means that either my expectation is buggy, or something else is 
> > buggy.

The "buggy" thing is
<https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/Other-Builtins.html>:

  Built-in Function: double __builtin_powi (double, int)
  Returns the first argument raised to the power of the second. Unlike the pow
  function no guarantees about precision and rounding are made.

GCC's <cmath> header do different thing for C++11 and C++03.  In C++03,
`double std::pow(double, int)` is implemented by `__builtin_powi`.  In C++11,
it is implemented by casting the second parameter to double, and then call
`pow(double, double)` from libc.

The C++11 behavior is defined by 26.8 [c.math] para 11:

> Moreover, there shall be additional overloads sufficient to ensure:
> 1. If any argument corresponding to a double parameter has type long
> double, then all arguments corresponding to double parameters are
> effectively cast to long double.
> 2. Otherwise, if any argument corresponding to a double parameter has
> type double or an integer type, then all arguments corresponding to
> double parameters are effectively cast to double.
> 3. Otherwise, all arguments corresponding to double parameters are
> effectively cast to float.

And libstdc++ is doing right thing (casting the `int` parameter to
`double`).  But C++03 is not so clear and does not define what should
libstdc++ do.  Libstdc++ chooses to call __builtin_powi.  Unfortunately
it is not so precise.

> > Note 1:
> > If the "-ansi" switch is omitted, then the output matches my expectation.

"-ansi" means "-std=c++98".  Now GCC is defaulted to C++14.

> Don't use -ansi, use -std= . Most likely you did not mean to use 
> -std=c++98.
> 
> The exact set of overloads of pow in the C++ standard has varied with 
> time, https://en.cppreference.com/w/cpp/numeric/math/pow gives some idea.
> 
> > Note 2:
> > If cmath is #included instead of math.h, then the output matches my
> > expectation.
> 
> If you include cmath and not math.h, you should use std::pow.

Yes.  std::pow gives the same "buggy" output.

But, I wonder why don't we change the C++98/03 `pow` behavior to be same
as C++11?  This is still standard and is more precise.

Jonathan how do you think?
-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: A g++ bug ... or not ?
  2018-09-07 15:43   ` Xi Ruoyao
@ 2018-09-07 22:48     ` Jonathan Wakely
  2018-09-08  1:58     ` sisyphus1
  1 sibling, 0 replies; 7+ messages in thread
From: Jonathan Wakely @ 2018-09-07 22:48 UTC (permalink / raw)
  To: xry111; +Cc: sisyphus1, gcc-help

On Fri, 7 Sep 2018 at 16:43, Xi Ruoyao wrote:
>
> On 2018-09-07 17:03 +0200, Marc Glisse wrote:
> > On Sat, 8 Sep 2018, sisyphus1@optusnet.com.au wrote:
> >
> > > Hi,
> > >
> > > The demo program:
> > >
> > > /****/
> > > /* try.c */
> > > #include <stdio.h>
> > > #include <math.h>
> > >
> > > int main(void) {
> > >
> > > int x = -1074;
> > >
> > > printf("%e\n", pow (2.0, (double)x));
> > > printf("%e\n", pow (2.0, x));
> > >
> > > return 0;
> > > }
> > >
> > > /****/
> > >
> > > If I build that program (using g++ version 7.3.0) with "g++ -ansi -o try
> > > try.c" I get output of:
> > >
> > > 4.940656e-324
> > > 0.000000e+000
> > >
> > > whereas I expected output to be:
> > >
> > > 4.940656e-324
> > > 4.940656e-324
> > >
> > > I guess that means that either my expectation is buggy, or something else is
> > > buggy.
>
> The "buggy" thing is
> <https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/Other-Builtins.html>:
>
>   Built-in Function: double __builtin_powi (double, int)
>   Returns the first argument raised to the power of the second. Unlike the pow
>   function no guarantees about precision and rounding are made.
>
> GCC's <cmath> header do different thing for C++11 and C++03.  In C++03,
> `double std::pow(double, int)` is implemented by `__builtin_powi`.  In C++11,
> it is implemented by casting the second parameter to double, and then call
> `pow(double, double)` from libc.
>
> The C++11 behavior is defined by 26.8 [c.math] para 11:
>
> > Moreover, there shall be additional overloads sufficient to ensure:
> > 1. If any argument corresponding to a double parameter has type long
> > double, then all arguments corresponding to double parameters are
> > effectively cast to long double.
> > 2. Otherwise, if any argument corresponding to a double parameter has
> > type double or an integer type, then all arguments corresponding to
> > double parameters are effectively cast to double.
> > 3. Otherwise, all arguments corresponding to double parameters are
> > effectively cast to float.
>
> And libstdc++ is doing right thing (casting the `int` parameter to
> `double`).  But C++03 is not so clear and does not define what should
> libstdc++ do.  Libstdc++ chooses to call __builtin_powi.  Unfortunately
> it is not so precise.
>
> > > Note 1:
> > > If the "-ansi" switch is omitted, then the output matches my expectation.
>
> "-ansi" means "-std=c++98".  Now GCC is defaulted to C++14.
>
> > Don't use -ansi, use -std= . Most likely you did not mean to use
> > -std=c++98.
> >
> > The exact set of overloads of pow in the C++ standard has varied with
> > time, https://en.cppreference.com/w/cpp/numeric/math/pow gives some idea.
> >
> > > Note 2:
> > > If cmath is #included instead of math.h, then the output matches my
> > > expectation.
> >
> > If you include cmath and not math.h, you should use std::pow.
>
> Yes.  std::pow gives the same "buggy" output.
>
> But, I wonder why don't we change the C++98/03 `pow` behavior to be same
> as C++11?  This is still standard and is more precise.
>
> Jonathan how do you think?

Maybe. I think that might resolve
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78851 too

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: A g++ bug ... or not ?
  2018-09-07 15:43   ` Xi Ruoyao
  2018-09-07 22:48     ` Jonathan Wakely
@ 2018-09-08  1:58     ` sisyphus1
  2018-09-08  2:59       ` Xi Ruoyao
  1 sibling, 1 reply; 7+ messages in thread
From: sisyphus1 @ 2018-09-08  1:58 UTC (permalink / raw)
  To: Xi Ruoyao; +Cc: gcc-help, Jonathan Wakely

-----Original Message----- 
From: Xi Ruoyao
Sent: Saturday, September 08, 2018 1:43 AM
To: sisyphus1@optusnet.com.au
Cc: gcc-help@gcc.gnu.org ; Jonathan Wakely
Subject: Re: A g++ bug ... or not ?

[snip]

> And libstdc++ is doing right thing (casting the `int` parameter to 
> `double`).  But C++03 is not so clear and does not define what should 
> libstdc++ do.  Libstdc++ chooses to call __builtin_powi.  Unfortunately it 
> is not so precise.

Based on that, I expected that another solution to the problem (ie instead 
of providing the explicit cast to double) would be to compile with 
"-fno-builtin".
So I tried building the demo with "g++ -fno-builtin -std=c++03 -o try 
try.c", but the explicit cast to double was still required.

> "-ansi" means "-std=c++98".  Now GCC is defaulted to C++14.
>
>> Don't use -ansi, use -std= . Most likely you did not mean to use 
>> std=c++98.

The current perl5 source contains a pow call that raises 2.0 to an "int" 
power.
When (and only when) perl is built with recent g++, that pow() call will 
return 0 whenever it should be returning a subnormal value. (No problems 
with normal values.)
I'm not sure how the "-ansi" switch is being invoked for the building of 
perl with g++, and I'll check on that.

I think the solution of providing the explicit cast is ok, but I had kept 
wondering whether the behaviour was something that should be reported to the 
gcc developers.
In the replies received, I've also gained a better understanding of what's 
going on - and I thank you for that.

I very rarely have any involvement with the g++ compiler (or C++ code), but 
this particular perl5 bug grabbed my interest.

Cheers,
Rob


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: A g++ bug ... or not ?
  2018-09-08  1:58     ` sisyphus1
@ 2018-09-08  2:59       ` Xi Ruoyao
  2018-09-08  5:34         ` Xi Ruoyao
  0 siblings, 1 reply; 7+ messages in thread
From: Xi Ruoyao @ 2018-09-08  2:59 UTC (permalink / raw)
  To: sisyphus1, Jonathan Wakely; +Cc: gcc-help, Vadim Zeitlin

On 2018-09-08 11:58 +1000, Rob <sisyphus1@optusnet.com.au> wrote:
> -----Original Message----- 
> From: Xi Ruoyao
> Sent: Saturday, September 08, 2018 1:43 AM
> To: sisyphus1@optusnet.com.au
> Cc: gcc-help@gcc.gnu.org ; Jonathan Wakely
> Subject: Re: A g++ bug ... or not ?
> 
> [snip]
> 
> > And libstdc++ is doing right thing (casting the `int` parameter to 
> > `double`).  But C++03 is not so clear and does not define what should 
> > libstdc++ do.  Libstdc++ chooses to call __builtin_powi.  Unfortunately it 
> > is not so precise.
> 
> Based on that, I expected that another solution to the problem (ie instead 
> of providing the explicit cast to double) would be to compile with 
> "-fno-builtin".
> So I tried building the demo with "g++ -fno-builtin -std=c++03 -o try 
> try.c", but the explicit cast to double was still required.

No.  That won't work because libstdc++ is *explicitly* calling
`__builtin_powi`.  `-fno-builtin` can only stop GCC to convert, for e.g.
`printf(...)` to `__builtin_printf(...)`.

On Fri, 7 Sep 2018 23:47:48 +0100, Jonathan Wakely wrote:

> Maybe. I think that might resolve
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78851 too

We both try to make C++11 and C++03 behavior consistent but Vadim intend
to use __builtin_pow for both of them...  I believe he is wrong because
Rob has shown that __builtin_pow is inprecise and evil.  And, C++11
*defines* `double pow(double x, int y)` to behave *exactly* whatv
`pow(x, (double)y)` does.

Like Marc, I can't reproduce Vadim's result and think Vadim's libm is
buggy.

I'll try to make C++03 `pow(float, int)`, `pow(double, int)` and
`pow(long double, int)` to call libm functions instead of builtin
functions, then do a regression test.
-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: A g++ bug ... or not ?
  2018-09-08  2:59       ` Xi Ruoyao
@ 2018-09-08  5:34         ` Xi Ruoyao
  0 siblings, 0 replies; 7+ messages in thread
From: Xi Ruoyao @ 2018-09-08  5:34 UTC (permalink / raw)
  To: sisyphus1, Jonathan Wakely; +Cc: gcc-help, Vadim Zeitlin

On 2018-09-08 10:59 +0800, Xi Ruoyao wrote:
> On Fri, 7 Sep 2018 23:47:48 +0100, Jonathan Wakely wrote:
> 
> > Maybe. I think that might resolve
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78851 too
> 
> We both try to make C++11 and C++03 behavior consistent but Vadim intend
> to use __builtin_pow for both of them...  I believe he is wrong because
> Rob has shown that __builtin_pow is inprecise and evil.  And, C++11
> *defines* `double pow(double x, int y)` to behave *exactly* whatv
> `pow(x, (double)y)` does.
> 
> Like Marc, I can't reproduce Vadim's result and think Vadim's libm is
> buggy.
> 
> I'll try to make C++03 `pow(float, int)`, `pow(double, int)` and
> `pow(long double, int)` to call libm functions instead of builtin
> functions, then do a regression test.

It's difficult to do for `__builtin_powif` because casting `int` to
`float` will lose precision.

See also PR11706, PR48738, 32503, and 72099.  Someone demends even
more "optimization" while the others demends precision.  In my point
of view such "optimizations" should only be applied with
`-ffast-math`, unless we can prove they won't lose precision.
-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2018-09-08  5:34 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-07 14:27 A g++ bug ... or not ? sisyphus1
2018-09-07 15:03 ` Marc Glisse
2018-09-07 15:43   ` Xi Ruoyao
2018-09-07 22:48     ` Jonathan Wakely
2018-09-08  1:58     ` sisyphus1
2018-09-08  2:59       ` Xi Ruoyao
2018-09-08  5:34         ` Xi Ruoyao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).