我正在开发一些线性代数代码,这些代码在
矩阵系数类型。一种可能的类型是要执行的类
模运算,天真的实现如下:
template<typename val_t> // `val_t` is an integer type
class Modular
{
val_t val_;
static val_t modulus_;
public:
Modular(const val_t& value) : val_(value) { };
static void global_set_modulus(const val_t& modulus) { modulus_ = modulus; };
Modular<val_t>& operator=(const Modular<val_t>& other) { val_ = other.val_; return *this; }
Modular<val_t>& operator+=(const Modular<val_t>& other) { val_ += other.val_; val_ %= modulus_; return *this; }
Modular<val_t>& operator-=(const Modular<val_t>& other) { val_ -= other.val_; val_ %= modulus_; return *this; }
Modular<val_t>& operator*=(const Modular<val_t>& other) { val_ *= other.val_; val_ %= modulus_; return *this; }
Modular<val_t>& operator/=(const Modular<val_t>& other) { val_ *= other.inverse().val_; val_ %= modulus_; return *this; }
friend Modular<val_t> operator+(const Modular<val_t>& a, const Modular<val_t>& b) { return Modular<val_t>((a.val_ + b.val_) % Modular<val_t>::modulus_); };
friend Modular<val_t> operator-(const Modular<val_t>& a, const Modular<val_t>& b) { return Modular<val_t>((a.val_ - b.val_) % Modular<val_t>::modulus_); };
// ...etc.
};
但是,当程序以
Modular<int>
系数运行时,它是几个比使用
int
系数运行时慢两倍。我应该在“模块化”类中更改哪些内容
为了获得最佳性能?
例如,是否可以优化诸如
a*b + c*d
的表达式到
(a.val_*b.val_ + c.val_*d.val_) % modulus
,而不是obvious:(((a.val_*b.val_) % modulus) + ((c.val_*d.val_ % modulus) % modulus) % modulus)
最佳答案
是。有可能的。您要查找的是“表达式模板”,然后从那里开始。从那时起,您将必须构建一些元程序逻辑来优化/简化表达式。这项任务远非琐事,但这不是您要的。
NVM-这很简单:
int count = 0;
int modulus() { count++; return 10; }
template < typename T >
struct modular
{
modular(T v) : value_(v) {}
T value() const { return value_; }
void value(T v) { value_ = v; }
typedef modular<T> modular_type;
typedef T raw_type;
private:
T value_;
};
template < typename LH, typename RH >
struct multiply
{
multiply(LH l, RH r) : lh(l), rh(r) {}
typedef typename LH::modular_type modular_type;
typedef typename LH::raw_type raw_type;
raw_type value() const { return lh.value() * rh.value(); }
operator modular_type () const { return modular_type(value() % modulus()); }
private:
LH lh; RH rh;
};
template < typename LH, typename RH >
struct add
{
add(LH l, RH r) : lh(l), rh(r) {}
typedef typename LH::modular_type modular_type;
typedef typename LH::raw_type raw_type;
raw_type value() const { return lh.value() + rh.value(); }
operator modular_type () const { return modular_type(value() % modulus()); }
private:
LH lh; RH rh;
};
template < typename LH, typename RH >
add<LH,RH> operator+(LH const& lh, RH const& rh)
{
return add<LH,RH>(lh,rh);
}
template < typename LH, typename RH >
multiply<LH,RH> operator*(LH const& lh, RH const& rh)
{
return multiply<LH,RH>(lh,rh);
}
#include <iostream>
int main()
{
modular<int> a = 5;
modular<int> b = 7;
modular<int> c = 3;
modular<int> d = 8;
std::cout << (5*7+3*8) % 10 << std::endl;
modular<int> result = a * b + c * d;
std::cout << result.value() << std::endl;
std::cout << count << std::endl;
std::cin.get();
}
如果您很聪明,则可以在模块化的构造函数中使用%,因此它始终是模块化的。您还需要进行检查,以确保LH和RH与SFINAE废话兼容,以防止运算符(operator)随时杀死它。您也可以将模数作为模板参数,并提供元函数来访问它。无论如何...你去了。
编辑:顺便说一句,您可以使用相同的技术来使矩阵计算更快。进行这些操作,而不是为操作字符串中的每个操作创建新的矩阵,然后在分配结果时逐个元素地进行数学运算。互联网上的所有内容都有相关论文,将其与FORTRAN等进行了比较。是元编程的最早用途之一,例如C++中的模板用途。同样在http://www.amazon.com/Scientific-Engineering-Introduction-Advanced-Techniques/dp/0201533936
关于c++ - 在C++中优化模块化算术计算,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4433891/