【问题标题】:std::pow() output is... special?std::pow() 输出是……特别的?
【发布时间】:2013-10-22 13:08:42
【问题描述】:

嘿,这一切希望是一个简单的问题来回答,但这对我来说是全新的,我不知道为什么会这样。取下面的C++代码:

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;
}

输出是:

3.125e+008
312500000

两者都是正确的,但std::pow() 将输出格式化为科学计数法。它到底是怎么做到的? C++ 一定有一个我一直缺少的特性。救命!

【问题讨论】:

  • 不知道std::pow 是一个模板。你确定可以编译?
  • 您不应该为这些函数显式指定模板参数。
  • @LuchianGrigore:允许但不需要是模板。所以它编译了一些地方,但不是所有地方。
  • @LuchianGrigore - 它不是必须作为模板,如果是,则显式特化它的效果不是由 C++ 标准定义的。
  • @PeteBecker 我怀疑它在gccclang 上使用了complex 版本,此代码std::cout &lt;&lt; typeid( std::pow&lt;size_t&gt;(50, 5)).name() &lt;&lt; std::endl; 返回ddouble

标签: c++ templates format pow


【解决方案1】:

pow的返回类型不管是什么类型的输入都是double/floatexpo的返回类型是size_t,因为编译器为size_t实例化了expo。 您可以使用std::fixed 将双重格式设置为非科学。

重要更新:

在 gcc 中有一个 pow 的模板基声明(我不确定它是否标准),它接受类型:

  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));
    }

返回值为double/float

【讨论】:

  • 我需要进行更多研究,因为我实际上没有看到双精度/浮点转换。例如,我不确定 __promote_2 或 __type 或 __variable 应该做什么。学习的东西!大声笑
  • @Parad0x13:您不必了解这些实施细节。我证明只是说模板库 pow 存在于 gcc 中(也许它是一个扩展)
  • 我很确定我的测试中的promote_2 正在执行26.8.11 的要求。您可以看到它here 第 192 行并返回,您可以看到它会按照标准要求将 integral 转换为 double
  • @MM。我知道,但我真的很想了解 Cpp(我最喜欢的语言)的一切可能
【解决方案2】:

所以基本的答案是:

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

正在返回一个 double,因此输出默认为 scientific 格式。如果我们查看关于 cppreference it claims 的文档,自 C++11 *integral* 参数被转换为 double 并且输出为这些情况应该是double。我无法从标准中确定一个强有力的声明,但输出与该解释一致。

我们可以使用std::typeid 确认至少gccclang 的输出确实是double

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

当我们通过c++filt -t d 运行它时输出d 它告诉我们它是double

更新

draft C++ standard 中找到相关部分。如果我们查看 26 Numerics library 部分,然后转到包含 &lt;cmath&gt; 标头的 26.8 C library 部分,它指定了数学函数的重载floatdoublelong double,在第 8 段中介绍:

除了 中的数学函数的 double 版本外,C++ 还添加了这些函数的 float 和 long double 重载版本,具有相同的语义。

它涵盖了第 11 段中的 整体 案例,其中说(强调我的):

此外,应有足够的额外重载以确保:

  1. 如果对应于 double 参数的任何算术参数的类型为 long double,则对应于 double 参数的所有算术参数都将有效地转换为 long double。
  2. 否则,如果任何对应于 double 参数的算术参数具有 double 类型或整数类型,则对应于 double 参数的所有算术参数都将有效地转换为 double。
  3. 否则,对应于双精度参数的所有算术参数都具有浮点类型。

【讨论】:

  • 谢谢沙菲克!我需要学习如何更好地搜索文档
  • @Parad0x13 cppreference 是一个很好的起点,它通常是准确的,尽管有时会丢失示例。
  • @ShafikYaghmour:原因比看起来容易,请阅读我的回答。
  • @MM。很好的挖掘,我调查了它,__promote_2 看起来像gcc 实现了26.8 p 11 中列出的要求,它将调用__promote,它将采用 integral 类型到 .
猜你喜欢
  • 1970-01-01
  • 2013-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多