C++ 在C+中使用两个输入来记忆函数+;
我有一个函数,C++ 在C+中使用两个输入来记忆函数+;,c++,C++,我有一个函数,f(a,b),它接受两个输入。我事先不知道将使用a和b的哪些值。我不介意在记忆上有点浪费(我在乎速度)。我希望能够检查f(a,b)的输出是否已经交付,如果已经交付,则在不重新运行f(a,b)过程的情况下再次交付该输出 在Python中使用装饰器是很容易的,但是C++在我的脑子里是这样的。 < P>我会使用(或者也许是 STD::unOrdEdjPad < /COD>),其键是A,或者可能使用地图。 在这种情况下,C++11的改进可能会有所帮助。或者一些增强功能。使用C++11,您可
f(a,b)
,它接受两个输入。我事先不知道将使用a
和b
的哪些值。我不介意在记忆上有点浪费(我在乎速度)。我希望能够检查f(a,b)
的输出是否已经交付,如果已经交付,则在不重新运行f(a,b)
过程的情况下再次交付该输出
在Python中使用装饰器是很容易的,但是C++在我的脑子里是这样的。
< P>我会使用(或者也许是<代码> STD::unOrdEdjPad < /COD>),其键是A,或者可能使用地图。在这种情况下,C++11的改进可能会有所帮助。或者一些增强功能。使用C++11,您可以使用任务和未来。让
f
成为您的功能:
int f(int a, int b)
{
// Do hard work.
}
然后,您将计划函数执行,这将返回返回值的句柄。此句柄称为未来:
免责声明:我的编译器不支持任务/未来,因此代码可能有一些粗糙的边缘。海报要求:
我希望能够检查f(a,b)的输出是否已经交付,如果已经交付,则在不重新运行f(a,b)进程的情况下再次交付该输出
在C++中使用一个<代码> STD::MAP< /COD>很容易。函数正好有两个参数,这意味着我们可以使用std::pair
来描述它们
#include <map>
#include <iostream>
uint64_t real_f(int a, int b) {
std::cout << "*";
// Do something tough:
return (uint64_t)a*b;
}
uint64_t memo_f(int a, int b) {
typedef std::pair<int, int> key;
typedef std::map<key, uint64_t> map;
static map m;
key k(a,b);
map::iterator it = m.find(k);
if(it == m.end()) {
return m[k] = real_f(a, b);
}
return it->second;
}
int main () {
std::cout << memo_f(1, 2) << "\n";
std::cout << memo_f(3, 4) << "\n";
std::cout << memo_f(1, 2) << "\n";
std::cout << memo_f(3, 4) << "\n";
std::cout << memo_f(5, 6) << "\n";
}
不带星号的行表示缓存的结果。这个问题的要点是计算f(a,b)和保留某种查找表以缓存结果之间CPU和RAM的相对开销 由于128位索引长度的详尽表格(目前)不可行,我们需要将查找空间缩小到可管理的大小-如果没有应用程序内部的一些考虑,这是无法做到的:
- 功能输入的实际使用空间有多大?这里面有规律吗
- 时间成分呢?您是否希望重复的计算彼此接近或沿时间线分布
- 分布情况如何?您是否假设索引空间的一小部分会占用大部分函数调用
(a,b,f(a,b))
元组数组和一个线性搜索开始。根据上面提到的模式,您可能希望
- 窗口滑动(在缓存未命中时删除最旧的):这对于本地化的重新发生很好
- have
具有最小计数的元组的元组被排除-这对于非本地化的事件很好(a,b,f(a,b),count)
- 让一些键函数确定缓存中的位置(这有利于索引空间的使用)
- 无论Knuth或Google想到了什么
如果查找机制变得越来越复杂,您可能还希望对重复计算进行基准测试:
std::map
和freinds不是免费的,即使它们是高质量的实现。唯一简单的方法是使用std::map
<代码>标准::无序映射不起作用。我们不能使用std::pair
作为无序映射中的键。您可以执行以下操作:
std::map<pair<int, int>, int> mp;
int func(int a, int b)
{
if (mp.find({a, b}) != mp.end()) return mp[{a, b}];
// compute f(a, b)...
mp[{a, b}] = // computed value;
return mp[{a, b}];
}
std::map-mp;
int func(int a,int b)
{
if(mp.find({a,b})!=mp.end())返回mp[{a,b}];
//计算f(a,b)。。。
mp[{a,b}]=//计算值;
返回mp[{a,b}];
}
输入的数据类型是什么?我写了一个无符号64位整数。到目前为止,这些答案似乎相当复杂。。。有没有一种方法可以让我声明一个二维向量,然后直接检索/设置它?@JohnSmith:你不能创建一个由单个64位整数索引的向量,更不用说两个了。您需要2**128
元素!只是预初始化它会非常慢。我认为这没有帮助。您仍然需要一种方法来查找与特定的(a,b)
元组对应的未来的对象,如果这样做,您可以只查找结果。@BenVoigt:如果f
便宜,我同意。但据我所知,f
的实际计算可能会很昂贵。小小的挑剔,m[k]
将进行另一次搜索,而m.find(k)
已经执行了。为了避免这一点,考虑使用<代码> m插入()< <代码> >或>代码> m(或)>代码>。为什么您认为我们不能使用<代码> STD::unOrdEdjPMAP?也许应该提供一个散列函数(我没有检查它),就是这样。是的,我们不能使用无序映射,除非你为它提供一个散列函数。
#include <map>
#include <iostream>
uint64_t real_f(int a, int b) {
std::cout << "*";
// Do something tough:
return (uint64_t)a*b;
}
uint64_t memo_f(int a, int b) {
typedef std::pair<int, int> key;
typedef std::map<key, uint64_t> map;
static map m;
key k(a,b);
map::iterator it = m.find(k);
if(it == m.end()) {
return m[k] = real_f(a, b);
}
return it->second;
}
int main () {
std::cout << memo_f(1, 2) << "\n";
std::cout << memo_f(3, 4) << "\n";
std::cout << memo_f(1, 2) << "\n";
std::cout << memo_f(3, 4) << "\n";
std::cout << memo_f(5, 6) << "\n";
}
*2
*12
2
12
*30
std::map<pair<int, int>, int> mp;
int func(int a, int b)
{
if (mp.find({a, b}) != mp.end()) return mp[{a, b}];
// compute f(a, b)...
mp[{a, b}] = // computed value;
return mp[{a, b}];
}