表格查找10的权力

时间:2017-02-15 00:21:24

标签: c++ optimization

我正在开发一个C ++项目,其中计算速度至关重要。任何时候我都可以削减,应该削减。可执行文件的最终大小和内存使用量不是 重要。

话虽如此,创建一个10的幂的预先计算的查找表是否有益?例如,如果我有这个简化的功能:

double powTen(int exponent) {
    return pow(10, exponent);
}

如果用表查找替换pow(),它会有(小)性能提升吗?它甚至值得吗?似乎pow()函数必须相当复杂。此外,GCC是否对此进行了特殊优化?

3 个答案:

答案 0 :(得分:1)

使用循环可以使函数更有效:

[HttpGet]
[Route("/Discussion/Export")]
public IActionResult GetDataAsCsv()
{
    var forums = _discussionService.GetForums(_userHelper.UserId);

    var csvFormatter = new CsvOutputFormatter(new CsvFormatterOptions());

    var stream = csvFormatter.GetStream(forums);
    return File(stream, "application/octet-stream", "forums.csv");

    //is the stream Disposed here automatically?
}

循环的一个好处是您要删除double powerTen(int exponent) { double result = 1.0; for (int i = 0; i < exponent; ++i) { result = result * 10.0; } return result; } 函数的函数调用开销。 IMO没有太多的节省。

另一种选择是表格查找:

pow

您正在为执行时间交易内存空间 此外,您可能希望添加一些数组溢出检查以及处理负指数。

答案 1 :(得分:0)

你这么称呼这个功能吗?如果是这样,那么预期值的预先计算会更好。

您还可以使用部分构建的表并使用构建,即。第一次10 ^ 5调用计算它,然后保存在表中,以便下次从表中获取。

使用table总是比调用一个函数更好,但事情是它必须首先通过多次调用,或者多次发送相同的参数,以便你最终不会调用函数时间,然后根本不使用,这将破坏你最小的优化的第一个意图。

答案 2 :(得分:0)

表查找几乎总是很好的性能。因此,假设您已将此识别为瓶颈,我将使用时间来实现生成表的模板。然而,要衡量一下。性能在现代计算机上是一种奇怪的野兽。它可以走向人们永远不会相信的方向。

我预计实现编译时生成表的时间确实非常短。但事实证明,至少从旧的更新2开始,Visual C ++ 2015对于类中的constexpr std::array并不满意。但是,最后,一个原始数组工作。

代码,使用MinGW g ++ 6.3.0和Visual C ++ 2015 update 2编译:

#include <stddef.h>     // size_t, ptrdiff_t
#include <utility>      // std::(make_index_sequence, )

namespace my {
    using std::make_index_sequence;
    using std::index_sequence;

    using Size = ptrdiff_t;

    template< Size n, class Item >
    using raw_array_of_ = Item[n];

    template< class Item, size_t n >
    constexpr
    auto n_items_of( raw_array_of_<n, Item>& )
        -> Size
    { return n; }

    namespace impl {
        constexpr
        auto compile_time_pow_of_10( int const n )
            -> double
        { return (n == 0? 1.0 : 10.0*compile_time_pow_of_10( n - 1 )); }

        template< size_t... indices >
        struct Powers_of_10_
        {
            static constexpr size_t                     n       = sizeof...(indices);
            static constexpr raw_array_of_<n, double>   table   =
            {
                compile_time_pow_of_10( indices )...
            };

            constexpr
            Powers_of_10_() {}
        };

        template< size_t... indices >
        constexpr
        raw_array_of_<Powers_of_10_<indices...>::n, double>
            Powers_of_10_<indices...>::table;

        template< size_t... indices, int n = sizeof...(indices) >
        constexpr
        auto power_of_10_table_helper( index_sequence<indices...> )
            -> const raw_array_of_<n, double>&
        { return Powers_of_10_<indices...>::table; }
    }  // namespace impl

    template< int n >
    constexpr
    auto power_of_10_table()
        -> const raw_array_of_<n, double>&
    { return impl::power_of_10_table_helper( make_index_sequence<n>() ); }

}  // namespace my

#include <iostream>
using namespace std;
auto main()
    -> int
{
    int const n = 7;
    constexpr auto& pow_10 = my::power_of_10_table<n>();

    cout << n << " powers of 10:\n";
    cout << fixed;  cout.precision( 0 );
    for( int i = 0; i < n; ++i )
    {
        cout << pow_10[i] << "\n";
    }
}

模板代码很难移植。即:Visual C ++ 2015拒绝接受上述代码中的std::array,因此需要重写以使用原始数组。由于通常过于冗长和神秘的编译诊断,它也很难维护。

可以通过将幂表示为 x 形式的幂的乘积来定义相当快的积分幂函数(2 n 。例如, x 42 = x 32 · x 8 < / sup>⋅ x 2 x 的这些更基本的幂,即2,8和32,可以通过反复平方来计算 X 。这减少了从指数线性到指数对数的乘法次数。

代码:

#include <stddef.h>     // size_t, ptrdiff_t

namespace my {
    using Size = ptrdiff_t;

    template< Size n, class Item >
    using raw_array_of_ = Item[n];

    namespace impl {
        auto positive_integral_power_of( const double x, const int n )
        {
            double result = 1.0;
            double power = x;
            for( unsigned exp = n; ; )
            {
                if( (exp & 1) != 0 )
                {
                    result *= power;
                }
                exp >>= 1;
                if( exp == 0 )
                {
                    break;
                }
                power *= power;
            }
            return result;
        }
    }  // namespace impl

    auto integral_power_of( const double x, const int n )
        -> double
    {
        return
            n > 0? 
                impl::positive_integral_power_of( x, n ) :
            n < 0?
                1.0 / impl::positive_integral_power_of( x, -n ) :
            1.0;
    }
}  // namespace my

#include <iostream>
using namespace std;
auto main()
    -> int
{
    int const n = 7;
    cout << n << " powers of 10:\n";
    cout << fixed;  cout.precision( 0 );
    for( int i = 0; i < n; ++i )
    {
        cout << my::integral_power_of( 10, i ) << "\n";
    }
}