A g++ bug ... or not ?

Xi Ruoyao xry111@mengyan1223.wang
Fri Sep 7 15:43:00 GMT 2018


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



More information about the Gcc-help mailing list