質問

Hey all this hopefully is a simple question to answer but it's something entirely new to me and I have no idea why it's happening. Take the following C++ code:

template<class T>
T expo(T a, T b){
    T result = 1;
    while(b) {
        if(b & 1)result *= a;
        b >>=1 ;
        a *= a;
    }
    return result;
}

int main() {
    cout << std::pow<size_t>(50, 5) << endl;
    cout << expo<size_t>(50, 5) << endl;
}

The output is:

3.125e+008
312500000

Both are correct but the std::pow() formats the output into scientific notation. How in the world does it do this? There must be a feature of C++ that I've been missing. Help!

役に立ちましたか?

解決 2

So the basic answer is that:

std::pow<size_t>(50, 5)

is returning a double and therefore the output is defaulting to scientific format. If we look at the documentation on cppreference it claims the since C++11 *integral* arguments are cast to double and the output for these cases should be double. I am having trouble pinning that strong a statement from the standard but the output is consistent with that explanation.

We can confirm that the output is indeed double for at least gcc and clang using std::typeid:

std::cout << typeid( std::pow<size_t>(50, 5)).name() << std::endl;

which output d when we run that through c++filt -t d it tells us that it is double.

Update

Found the relevant section in the draft C++ standard. If we look in section 26 Numerics library and then go to section 26.8 C library which covers the <cmath> header, it specifies overloads of the math functions for float, double and long double which is covered in paragraph 8:

In addition to the double versions of the math functions in , C++ adds float and long double overloaded versions of these functions, with the same semantics.

and it covers the integral cases in paragraph 11 which says(emphasis mine):

Moreover, there shall be additional overloads sufficient to ensure:

  1. If any arithmetic argument corresponding to a double parameter has type long double, then all arithmetic arguments corresponding to double parameters are effectively cast to long double.
  2. Otherwise, if any arithmetic argument corresponding to a double parameter has type double or an integer type, then all arithmetic arguments corresponding to double parameters are effectively cast to double.
  3. Otherwise, all arithmetic arguments corresponding to double parameters have type float.

他のヒント

The return type of pow is double/float no matter what is the type of input, and the return type of expo is size_t because compiler instantiates expo for size_t. You can use std::fixed to make the double format to non-scientific.

Important update:

There is a template base declaration for pow in gcc (I'm not sure it's standard or not), and it accept types:

  template<typename _Tp, typename _Up>
    inline typename __gnu_cxx::__promote_2<_Tp, _Up>::__type
    pow(_Tp __x, _Up __y)
    {
      typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
      return std::pow(__type(__x), __type(__y));
    }

The return value is double/float.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top