实现数学函数C++的乘法运算
Implementing multiplication operator for mathematical functions C++
我有以下抽象基类:
class Function {
virtual double Eval(double x) const = 0;
};
我希望能够在我的主文件中使用像f*g或f->运算符*(g)这样的表达式,其中f和g是Function类的具体对象,例如,当我想计算一个定积分时,我可以写:
AnIntegrationMethod(f*g);
我提出的一个相当简单的方法是声明一个类Product(只显示了头文件,实现很明显):
class Product: public Function {
public: Product(Function *g, Function *f);
~Product();
virtual double Eval(double x) const; //return _g->Eval(x)*_f->Eval(x)
private: Function *_g; Function *_f;
};
然后在我的任何功能
#include "Product.h"
class ConcreteFunction: public Function {
public:
ConcreteFunction();
~ConcreteFunction();
virtual double Eval(double x) const;
Function* operator*(Function *f) {return new Product(this, f);}
};
这实际上适用于简单的东西,但问题是运算符*只在基类的单个派生类中定义,而不是为每个可能的派生类定义。例如,这意味着,如果我有一个表示数学函数的具体对象f,我可以调用f->运算符*g,但如果我想再次调用运算符*以获得对象(f->运算符*g)->运算符*f,我将无法调用,因为函数f*g没有定义为f的*运算符。
我想我应该直接在基类中定义运算符*,但我不知道如何实现运算符,因为我真的不知道如何为产品获得正确的Eval函数,因为我现在不能使用类product,在类function本身中使用从类function派生的类product是没有意义的。我想我也很困惑,写这样的东西是否正确:
Function* Function::operator*(Function *f) {
Function *g;
...
//operations that allow g to be have the right Eval function
//which should of the sort this->Eval(x) * f->Eval(x)
...
return g;
}
对于如何进行的任何提示或建议,我们将不胜感激。我的水平很基本,我已经编程两个月了。
只是一个草图,你可以做这样的事情:
#include <memory>
// Base Function: f(x) = x
class Function
{
protected:
struct Implementation
{
virtual ~Implementation() {}
virtual double evaluate(double x) const { return x; }
};
public:
Function()
: self(std::make_shared<Implementation>())
{}
double operator () (double x) const { return self->evaluate(x); }
protected:
Function(std::shared_ptr<Implementation> self)
: self(self)
{}
private:
std::shared_ptr<Implementation> self;
};
typedef Function Identity;
// Unary Function: u(-f(x))
class UnaryMinus : public Function
{
protected:
struct Implementation : Function::Implementation
{
Function f;
Implementation(Function f)
: f(f)
{};
virtual double evaluate(double x) const override { return -f(x); }
};
public:
UnaryMinus(Function f)
: Function(std::make_shared<Implementation>(f))
{}
};
// Binary Function: u(f(x) + g(x))
class BinaryAdd : public Function
{
protected:
struct Implementation : Function::Implementation
{
Function f;
Function g;
Implementation(Function f, Function g)
: f(f), g(g)
{};
virtual double evaluate(double x) const override { return f(x) + g(x); }
};
public:
BinaryAdd(Function f, Function g)
: Function(std::make_shared<Implementation>(f, g))
{}
};
// Binary Function: u(f(x) * g(x))
class BinaryMultiply : public Function
{
protected:
struct Implementation : Function::Implementation
{
Function f;
Function g;
Implementation(Function f, Function g)
: f(f), g(g)
{};
virtual double evaluate(double x) const override { return f(x) * g(x); }
};
public:
BinaryMultiply(Function f, Function g)
: Function(std::make_shared<Implementation>(f, g))
{}
};
inline UnaryMinus operator - (Function f) { return UnaryMinus(f); }
inline BinaryAdd operator + (Function f, Function g) { return BinaryAdd(f, g); }
inline BinaryMultiply operator * (Function f, Function g) { return BinaryMultiply(f, g); }
#include <iostream>
int main() {
Identity x;
Function result = -x * (x + x) + x;
std::cout << result(2) << 'n';
}
您可以将operator*
重载为独立函数。即使它不是Product
的成员,也要将它放在Product.h/cpp
中,因为它与CCD_3紧密相关。
在Product.h
:中
Function* operator*(Function *f, Function *g);
在Product.cpp
:中
Function* operator*(Function *f, Function *g) {
return new Product(f, g);
}
与加法、减法等相同
或者,您可以将它们实现为成员函数,但将定义放在Function.cpp
中,并在其中包含Product.h
等。
请注意您的设计有一个巨大的缺陷。在堆上创建new
Function对象,并传递指针。你需要在你的代码中的某个地方delete
它们,我想是在你的解构器中。但是,您还需要注意复制对象。通常,手动关心正确的删除是一场噩梦,而且有自动的方法(称为"内存管理")。例如,您可以考虑使用智能指针。看一下std::shared_ptr
。虽然不是在所有情况下都最有效,但当你第一次想学习语言时,通常使用它是一件好事,而不是太多关于内存管理的细节。要将shared_ptr
应用于代码,请将每个Function*
替换为shared_ptr<Function>
,并将new Function(...)
替换为CCD15(其他类型也是如此)。
还要注意数学函数的*
是模糊的:在一些上下文/文献中,f*g
的意思是乘以结果,而在另一些上下文/文学中,它的意思是函数卷积。
这里有一个C++11通用编程解决方案,它不依赖于继承的多态性(即虚拟函数),也不需要动态分配。
我不是C++专家,这可能会有很大的改进,但它很有效,并能让人理解这个想法。特别是,下面的代码只适用于double的函数。您可能也可以将操作数和返回类型设置为模板类型,这样就可以在不同的类型上通用(例如,complex)。我不知道确定模板运算符范围的正确方法,这样你就可以使用简写运算符表示法,而不会在其他具有运算符()(双x)的类型上意外调用它们(或使它们变得不明确)。如果有人对这个答案有任何改进的建议,请插话,我会编辑我的答案。
#include <iostream>
using namespace std;
struct Identity
{
double operator() (double x) const { return x; }
};
struct Constant
{
template<typename T1>
Constant(const T1 &x) : _x(x) {}
double operator()(double x) const { return _x; }
private:
double _x;
};
template<typename T1>
struct Negate
{
Negate(const T1 &f) : _f(f) {}
double operator() (double x) const { return -_f(x); }
private:
T1 _f;
};
template<typename T1>
struct Reciprocal
{
Reciprocal(const T1 &f) : _f(f) {}
double operator() (double x) const { return 1 / _f(x); }
private:
T1 _f;
};
template<typename T1, typename T2>
struct Sum
{
Sum(const T1 &f, const T2 &g) : _f(f), _g(g) {}
double operator() (double x) const { return _f(x) + _g(x); }
private:
T1 _f;
T2 _g;
};
template<typename T1, typename T2>
struct Product
{
Product(const T1 &f, const T2 &g) : _f(f), _g(g) {}
double operator() (double x) const { return _f(x) * _g(x); }
private:
T1 _f;
T2 _g;
};
template<typename T1>
Negate<T1> operator-(const T1 &f)
{ return Negate<T1>(f); }
template<typename T1, typename T2>
Sum<T1, T2> operator+(const T1 &f, const T2 &g)
{ return Sum<T1, T2>(f, g); }
template<typename T1, typename T2>
Sum<T1, Negate<T2> > operator-(const T1 &f, const T2 &g)
{ return Sum<T1, Negate<T2> >(f, Negate<T2>(g)); }
template<typename T1, typename T2>
Product<T1, T2> operator*(const T1 &f, const T2 &g)
{ return Product<T1, T2>(f, g); }
template<typename T1, typename T2>
Product<T1, Reciprocal<T2> > operator/(const T1 &f, const T2 &g)
{ return Product<T1, Reciprocal<T2> >(f, Reciprocal<T2>(g)); }
int main()
{
auto f = (Identity() * Constant(4.0) + Constant(5)) / Identity(); // f(x) = (x * 4 + 5) / x; f(2) = 6.5
auto g = f * f; // g(x) = f(x) * f(x); g(2) = 42.25
cout << f(2) << " " << g(2) << " " << (g / f)(2) << endl; // prints 6.5 42.25 6.5
return 0;
}
EDIT:这种方法的主要缺点是"公式"的类型必须在编译时完全已知,并嵌入到模板生成的类中。这意味着非常复杂的公式将生成许多不同的类和代码。因此,这种方法可能会导致严重的代码膨胀。此外,你不能做这样的事情:
for (i = 1; i < j; ++i) // raise f to the jth power (other than 0)
f *= f;
由于f的类型在编译时必须是完全已知的,并且乘法迭代地调用新的类型。其他使用类层次结构、动态分配(带自动清理)和多态性的方法可以做到这一点,并且不会出现代码膨胀的问题。尽管如此,尝试还是很有趣的。
- 使用C++中的模板和运算符重载执行矩阵运算
- GCC本机矩阵运算库
- 位阵列上的快速AND运算
- 字符串中int的加法运算
- 算术运算的结果类似于:C浮点变量中的1/3
- 如何使用OpenMP并行化此矩阵时间矢量运算
- 如何在两个 boost::multi_arrays (C++) 之间执行数学运算?
- 如何在 vtk Poly 数据上进行布尔运算?
- MSVC 无法根据模板参数进行数学运算,这是一个错误吗?
- 避免指针运算,修复叮当整齐错误
- 使用双精度的浮点运算
- 如何在 c++ 中使用带有数学运算的引用/指针?
- 更快的C++算术运算
- 是否存在用于 C 或 C++ 中常见数学运算(例如最小值、最大值和平均值)的可导入库?
- 为什么循环体中的一个基本算术运算执行得比两个算术运算慢
- 两个字符串之间的数学运算
- 为什么对无符号字符进行算术运算会将它们提升为有符号整数
- 何时使用按位运算而不是算术替代方法?
- Arduino 上数学运算的计时速度 - 异常
- 如何使用按位运算将随机uint64_t转换为范围 (0, 1) 的随机双精度