理论上通过组合STL仿函数能通过简单的语法完成强大的功能,一下是我自己写的6个仿函数。
/**
1. bind1 ( OP, arg) () : bind a unary_function to none argument function .
2. bind2 ( OP,arg1,arg2 ) () : bind a binary_function to none argument function .
3. compose_f_gx( OP1,OP2 ) (arg) : compose a function Op1( Op2( arg ) )
4. compose_f_gxy( OP1,OP2 ) (arg1,arg2) : compose a function OP1( OP2(arg1,arg2) )
5. compose_f_hx_gx( OP1,OP2,OP3 ) (arg) : compose a function OP1( OP2(arg) ,OP3(arg) )
6. compose_f_hx_gy( OP1,OP2,OP3) (arg1,arg2) : compose a function OP1( OP2(arg1) ,OP2(arg2) )
*/
#ifndef COMPOSE_H
#define COMPOSE_H
#include<functional>
using std::unary_function;
using std::binary_function;
/** 1.
* bind a unary_function to none argument function .
*/
template<class Operation>
class bind1
{
protected:
Operation op;
typename Operation::argument_type x;
public:
bind1( const Operation & _op,
const typename Operation::argument_type & _x )
:op( _op ), x( _x ){}
typename Operation::result_type
operator()() const { return op( x ) ; }
};
template<class Operation,class Arg>
inline bind1<Operation> bind1t(const Operation & op, const Arg & x)
{
return bind1<Operation>( op,typename Operation::argument_type( x ) ) ;
}
/** 2.
* bind a binary_function to none argument function .
*/
template<class Operation>
class bind2
{
protected:
Operation op;
typename Operation::first_argument_type x;
typename Operation::second_argument_type y;
public:
bind2(const Operation &_op ,
const typename Operation::first_argument_type &_x,
const typename Operation::second_argument_type &_y )
:op(_op),x(_x ),y(_y ){}
typename Operation::result_type
operator()() const{ return op(x,y) ; }
};
template<class Operation,class Arg1,class Arg2>
inline bind2<Operation> bind2t( const Operation &op, const Arg1 & x,const Arg2 &y )
{
return bind2<Operation>(op,
typename Operation::first_argument_type(x),
typename Operation::second_argument_type(y) );
}
/**3.
* compose function Op1( Op2( arg ) )
*/
template<class OP1,class OP2>
class compose_f_gx_t:
public unary_function<typename OP2::argument_type,typename OP1::result_type>
{
private:
OP1 op1;
OP2 op2;
public:
compose_f_gx_t(const OP1 &_op1, const OP2 &_op2)
:op1(_op1),op2(_op2){}
typename OP1::result_type
operator()(const typename OP2::argument_type & x ) const
{
return op1( op2(x) );
}
};
template<class OP1,class OP2>
inline compose_f_gx_t<OP1,OP2>
compose_f_gx(const OP1 & op1, const OP2 &op2)
{
return compose_f_gx_t<OP1,OP2>(op1,op2 );
}
/**4.
* compose_f_gxy( OP1,OP2 ) (arg1,arg2) : compose a function OP1( OP2(arg1,arg2) )
*/
template<class OP1,class OP2>
class compose_f_gxy_t:
public binary_function<typename OP2::first_argument_type ,
typename OP2::second_argument_type,
typename OP1::result_type>
{
private:
OP1 op1;
OP2 op2;
public:
compose_f_gxy_t(const OP1 &_op1, const OP2 &_op2):
op1(_op1),op2(_op2){}
typename OP1::result_type
operator()( const typename OP2::first_argument_type &x ,
const typename OP2::second_argument_type &y ) const
{
return op1( op2(x,y) );
}
};
template<class OP1,class OP2>
inline compose_f_gxy_t<OP1,OP2>
compose_f_gxy(const OP1 &op1, const OP2 &op2)
{
return compose_f_gxy_t<OP1,OP2>(op1,op2);
}
/**5.
* compose_f_hx_gx( OP1,OP2,OP3 ) (arg) : compose a function OP1( OP2(arg) ,OP3(arg) )
*/
template<class OP1,class OP2,class OP3>
class compose_f_hx_gx_t:public unary_function<typename OP3::argument_type, typename OP1::result_type >
{
private:
OP1 op1;
OP2 op2;
OP3 op3;
public:
compose_f_hx_gx_t(const OP1 &_op1, const OP2 &_op2, const OP3 & _op3 )
:op1(_op1),op2(_op2),op3(_op3) {}
typename OP1::result_type
operator()(const typename OP3::argument_type &x) const
{
return op1( op2(x),op3(x) );
}
};
template<class OP1,class OP2,class OP3>
inline compose_f_hx_gx_t<OP1,OP2,OP3>
compose_f_hx_gx(const OP1 &op1, const OP2 &op2,const OP3 &op3)
{
return compose_f_hx_gx_t<OP1,OP2,OP3>(op1,op2,op3) ;
}
/**6.
*compose_f_hx_gy( OP1,OP2,OP3) (arg1,arg2) : compose a function OP1( OP2(arg1) ,OP2(arg2) )
*/
template<class OP1,class OP2,class OP3>
class compose_f_hx_gy_t
:public binary_function< typename OP2::argument_type ,
typename OP3::argument_type ,
typename OP1::result_type>
{
private:
OP1 op1;
OP2 op2;
OP3 op3;
public:
compose_f_hx_gy_t(const OP1 &_op1, const OP2 & _op2, const OP3 &_op3)
:op1(_op1),op2(_op2),op3(_op3){}
typename OP1::result_type
operator()(typename OP2::argument_type &x ,
typename OP3::argument_type &y) const
{
return op1( op2(x),op3(y) );
}
};
template<class OP1,class OP2, class OP3>
inline compose_f_hx_gy_t<OP1,OP2,OP3>
compose_f_hx_gy(const OP1 &op1, const OP2 &op2,const OP3 &op3)
{
return compose_f_hx_gy_t<OP1,OP2,OP3>(op1,op2,op3);
}
#endif/*?end compose*/
如果一个函数如果可以用等号后面的东西表示出来的话,那么这个函数就是说,可以用泰勒展开式的方法展开来的。
在人类历史上,人类对泰勒展开式的兴趣之所以那么高,完完全全是因为(x-a)的n次方,(x-a)的n次方是多项式,多项式是当时人类最熟悉的函数形式之一。 但是在比较高等的数学里,我们有兴趣的完完全全是f(x)在a处的n阶导数这一项。这个n阶导数完全刻画出了泰勒展开式最重要的一个特征,叫做:“一叶知秋”。什么叫做“一叶知秋”,就是说一片叶子掉下来,我就知道秋天到了。好,f(x)在a处的n阶导数,导数的定义是什么,导数的定义是在x 趋近于a的时候在a的临域所发生的事情。f(x)在a处的n阶导数就是它的一阶变化率,二阶变化率,三阶变化率... 但是呢,它始终是在a的旁边一点点。我只要知道a点附近的这些东西,除以n的阶乘,再乘以(x-a)的n次方,我就完完全全可以知道函数在整个坐标系里的行为是什么,就知道了这个函数是什么。也就是说,我只要得到a附近的一点点的信息,我就可以知道这个函数长什么样子。 不只是这些,a还可以动,也就是说,函数上任意一点的临域都包含着函数的全部讯息!这就是泰勒展开式最重要的意义。 事实上泰勒展开式所研究的函数的种类,是数学上很稀少的一类,叫做解析函数。 我们的人生是解析函数吗?如果是的话,我们可以在最短最短时间内我们所经历的一切,外推到整个人生。所以说,如果人生是解析函数的话,那就太棒了。我们只要活一点点,我们就可以用一点点的生涯去幻想无穷无尽的生命到底是长什么样子。有一个我很敬佩的数学家,他说过一句话,“死并不可怕,死只是我所遇到的最后一个函数”。意思就是说,其实他认为人生并不是解析函数,他在那个时候已经认识到了,人生是充满着断点,跳跃,以及不连续点,人生是一个非常非常算是 正规的函数。因为事实上,Weierstrass已经证明:处处连续但处处不可微分的函数才是函数的常态。
无穷饭店 在基塔离开之前,他讲了一个稀奇的故事。
基塔:“无穷饭店”是我们银河系中心的一家巨大的旅馆。它拥有无穷多个房间,这些房间通过黑洞伸展到更高级的时空领域。房间号从1开始,无限制地排下去。 基塔:一天,这个旅店的客房全住进了客人,这时候来了一位飞碟(不明飞行物)的驾驶员,他正要去别的星系。 基塔:尽管已经没有空房间了,可是旅店老板仍然给驾驶员找到了一个房间。他不过是把原来住在各个房间里的房客都一一移到高一号的房间。于是左边第1号房间就空出来给该驾驶员住。 基塔:第二天又来了五对夫妇渡蜜月。无穷饭店能不能接待他们?可以,老板只不过把每个客人都一一移到高5号的房间中去,空出的1到5号房就给这5对夫妇 基塔:周末,又有无穷多个泡泡糖推销员来到这家旅馆开会。 赫尔曼:我能够理解无穷饭店可以怎样接待有限数量的新到者,可是它怎么能够再给无穷多旅客找到新房间呢? 基塔:很容易,我亲爱的赫尔曼。老板只要把每个房间里的客人移到原来号码两倍的房间中去就行了。 赫尔曼:对了!这下每个房间里的人都住到双号房中,余下的所有单号房间有无穷多个,它们空出来给泡泡糖商人住! 关于无穷大还有很多悖论。计数用的数是无穷大等级中最低一级的无穷数。在整个宇宙中的点数是第二级无穷大数,第三级无穷大数比这要多得多! 德国数学家乔治·康妥发现了无穷大的这种等级,他把这种新型的奇异等级称为阿列夫零、阿列夫1、阿列夫2等等。关于阿列夫数有很多深刻的神秘性,解决它们是现代数学中最激动人心的挑战之一。 如我们所知,任何一个有限集都不能与它的一个真子集建立一一对应的关系。对于无穷集这—点就不成立了。看上去这样就违反了整体大于局部这一古老法则。确实,一个无穷集可以定义为能够与它的一个真子集一一对应的集。 无穷饭店的老板首先表明了由一切计数用的数所组成的集合(这是乔治·康妥称为阿列夫零的集合)可以与它的某一个真子集一一对应,并余下一个元素,或者五个元素。显然,这一程序可以变化,使得从一个阿列夫零集中减去它的一个子集,这个子集也是阿列夫零集,从其余下的数中就会得到所要的任何有限个数量的元素。 还有一个办法可以使这一减法形象化,想象有两根无限长的测量棒并排放在桌子上,把两棍棒的零端对齐放在桌子中心。两根棒都刻了线,按厘米计数。两根棒在右端延伸到无穷远,所有数都一一对应:0—0、1—1、2—2等等。现在想象把一根棒向右移动n厘米。移动以后,那棍棒上的所有数仍与不动的棒上的数一一对应。如果那根棒移动了3厘米,则棒上教的对应就是0—3、1—4、2—5、……。移动的n厘米代表两棍棒长之差。不过,两根棒的长度仍然是阿列夫零厘米长。由于我们可以让二者之差n为我们所要的任何一个值,很明显用 阿列夫零减阿列夫零就是一个不确定的运算。 饭店老板最后施的策略就是打开无穷多个房间。这表明如何用阿列夫零减阿列夫零得到阿列夫零。让每一个数与每一个偶数一一对应,则余下的是一个由全部奇数所构成的阿列夫零集。 由实数所构成的集合形成更高一级的无穷集,康妥称之为阿列夫1。康妥的辉煌成就之一就是著名的“对角线证明”,它说的是阿列夫1的元素不可能与阿列夫1的元素构成一一对应关系。阿列夫1也就是在一条线段上全部点的数目。康妥证明了这些点怎样能与一条无限直线上的点一一对应,怎样与一方块上的点、与一无限大平面上的点;与一立方体中的点、与无限大空间中的点一一对应,如此下去还可以与超立方体或更高维空间中的点一一对应。阿列夫1又称为“连续统的势”。 阿列夫2是一切可能的数学函数——连续函数和不连续函数的数目。因为任何一个函数都可画为一曲线,我们把“曲线”取广义以包括不连续曲线,则阿列夫2就是一切可能的曲线数目。同样,如果我们所指的曲线是在一张邮票上,或者在一个无穷空间里,或者在一个无穷超空间里的全部曲线,这一切都没有问题,仍是阿列夫2。康妥还证明了阿列夫2不可能与阿列夫1一一对应。 当一个阿列夫数被升级为它本身的幂,则产生一个更高级的阿列夫数,它不能与产生它的阿列夫数一一对应。因此,阿列夫数的阶梯向上是无穷的。 在阿列夫数之间有没有什么超限数?比如说,有没有一个数比阿列夫零大、比阿列夫1小?康妥确信不存在这种数。他的猜测成为著名的广义连续统假设。 1938年,哥德尔证明标准集合论与不存在中介的超限数假设是一致的。1963年,保罗·科恩证明,如果人们假定存在中介数,这也不与集合论矛盾。简言之,连续统假设是由表明它是“不可判定的”来判定的。 科恩的研究结果是:集合论现在分为康妥型和非康妥型的。康妥型集合论是假设在阿列夫数之间没有中介数。非康妥型集合论是假定有无限多个中介数。情况类似于几何学中,发现平行线假设不能被证明后,几何学分成了欧氏几何和非欧几何一样。 希望学习更多关于这些神秘的超限数知识的学生可以阅读爱德华·卡斯纳和詹姆斯·纽曼著的《数学与想象力》第二章“古格尔之后”和《科学美国人》1966年三月号数学游戏部分