优化 BigInt 递归函数

Optimizing BigInt recursive function

本文关键字:递归函数 BigInt 优化      更新时间:2023-10-16

这是我使用maps编写的递归函数,它可以工作,但运行时间非常慢。如何优化此功能?

BigInt bitcon(int n)
{
static map<BigInt, BigInt> fiboMap;
BigInt bigN(n);
if (bigN == 1) return BigInt(100);
if (bigN == 2) return BigInt(200);
if (bigN == 3) return BigInt(300);
map<BigInt, BigInt>::iterator it = fiboMap.find(bigN);
if (it != fiboMap.end())
return it->second;
else
return fiboMap[bigN] = (BigInt(n) * (bitcon(n-1) + bitcon(n-2) - bitcon(n-3)));

以下内容:

#include <map>
#include <iostream>
#include <chrono>
struct BigInt {
unsigned long long n;
BigInt() : n(0) {}
BigInt(long long _n) : n(_n) {}
unsigned long long get() const { return n; }
bool operator==(long long other) const { return n == other; }
bool operator<(const BigInt &b) const { return get() < b.get(); }
BigInt operator+(const BigInt other) const { return BigInt(n + other.get()); }
BigInt operator-(const BigInt other) const { return BigInt(n - other.get()); }
BigInt operator*(const BigInt other) const { return BigInt(n * other.get()); }
};
BigInt bitcon(int n)
{
static std::map<BigInt, BigInt> fiboMap;
BigInt bigN(n);
if (bigN == 1) return BigInt(100);
if (bigN == 2) return BigInt(200);
if (bigN == 3) return BigInt(300);
std::map<BigInt, BigInt>::iterator it = fiboMap.find(bigN);
if (it != fiboMap.end())
return it->second;
else
return fiboMap[bigN] = (BigInt(n) * (bitcon(n-1) + bitcon(n-2) - bitcon(n-3)));
}
int main()
{
using namespace std::chrono;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
for(int i = 1; i < 100; ++i) {
std::cout <<i<<"->"<<bitcon(i).get()<<" ";
}
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = duration_cast<microseconds>( t2 - t1 ).count();
std::cout <<std::endl<<duration<<std::endl;
return 0;
}

在 www.onlinegdb.com 上以 117 微秒运行。可悲的是,我需要发明BigInt,因为你没有提供一个。
至于问题(下次请在问题"标题"中说明问题)使用静态映射是一个好主意,如果您多次计算相同的值。如果您不关心内存占用。使用递归也是可以的,如果你的堆栈很大。当您计算新值时,Map 会减慢您的速度,因为所有新的 (n-3) BigInt 对象都需要存储在此地图中。但是我会:

  • 不要使用map,只使用向量,fiboMap中的BitInt是有序的。无论如何,如果我需要使用映射,我会将整数映射到 BigInts,因为 int 是函数参数。
  • 不要将 bigN 与 1、2 和 3 进行比较(可能调用 BigInt 构造函数和/或运算符==),你为什么不比较n?此外,您可以使用 switch 语句,但无论如何,一个体面的编译器都应该进行优化。
  • 使用assert(n > 0);,我想你的函数不打算与n <= 0一起运行
  • 可能更喜欢 BigInt::operator*(
  • int) 而不是 BigInt::operator*(BigInt),但这取决于 BitInt 实现

但仅此而已,这并不多,这个功能还可以。所以,如果函数真的很慢,我猜 BigInt 中有一些慢的东西。

BigInt bitcon2(int n)
{
assert(n > 0);
switch(n) {
case 1: return BigInt(100);
case 2: return BigInt(200);
case 3: return BigInt(300);
}
static std::vector<BigInt> cache;
const int idx = n - 4;
if (cache.size() > idx)
return cache.at(idx);
BigInt ret = (bitcon(n-1) + bitcon(n-2) - bitcon(n-3)) * n;
cache.push_back(ret);
return ret;
}

但是,加速比(如果有的话)可以忽略不计。