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