我正在开发一个C ++项目,其中计算速度至关重要。任何时候我都可以削减,应该削减。可执行文件的最终大小和内存使用量不是 重要。
话虽如此,创建一个10的幂的预先计算的查找表是否有益?例如,如果我有这个简化的功能:
double powTen(int exponent) {
return pow(10, exponent);
}
如果用表查找替换pow()
,它会有(小)性能提升吗?它甚至值得吗?似乎pow()
函数必须相当复杂。此外,GCC是否对此进行了特殊优化?
答案 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";
}
}