细菌分裂问题:一个简单的混沌系统
假设有两种微生物X和Y,X出生后每隔3分钟分裂一次(数目加倍),Y出生后每隔2分钟分裂一次(数目加倍)。
一个新出生的X,半分钟之后吃掉1个Y,并且,从此开始,每隔1分钟吃1个Y。
现在已知有新出生的X=10, Y=89,求60分钟后Y的数目。
如果X=10,Y=90呢?
编程解决这个问题比较简单,只要以步长30秒不断进行迭代,直到时间到达60分钟即可。下面是用Java编写的程序。
整个程序分为4个类:
TestBacterium是测试主类。
Xs和Ys表示X和Y的集合,它们都包含divide()方法,执行分裂操作。
Xs有方法needToEat( ),返回在某个时间点,Xs需要吃多少个Ys;相应地,Ys有表示被吃的方法beenEaten( )。如果在某次被吃之后Ys的数量降至0,则beenEaten( )方法会抛出NoMoreYException异常。
Xs类
public class Xs { private int num ; public Xs(int num) { this.num = num; } public int needToEat(int time) { if (time <= 0) return 0; if (time % 60 == 30) return num; return 0; } public void divide(int time) { if (time <= 0) return; if (time % 180 == 0) { num *= 2; } } public int amount() { return num ; } }
这里要说明一下needToEat()方法。题目中说明:X出生后半分钟吃掉1个Y,之后每隔1分钟吃掉1个Y,并且每3分钟分裂一次。也就是说,X会在30、90、150秒的时间点上吃Y;接下来,在180秒时,会分裂一次,假设原来的为x1,新分裂出来的为x2,那么在下一个30秒,即在210秒时,x1和x2都要吃掉1个Y。发现规律了吗?实际上无论经过多久,每个X都会在(n分+30秒)的时间点上吃掉1个Y,并在180秒的整数倍时间点上分裂一次。
Ys类
public class Ys { private int num ; public Ys(int num) { this.num = num; } public void beenEaten(int eatenNum) throws NoMoreYException { if (num <= eatenNum) { num = 0; throw new NoMoreYException(); } num -= eatenNum; } public void divide(int time) { if (time <= 0) return; if (time % 120 == 0) { num *= 2; } } public int amount() { return num ; } }
TestBacterium类
public class TestBacterium { private Xs x; private Ys y; public TestBacterium(int numX, int numY) { x = new Xs(numX); y = new Ys(numY); } public void startTick(int timeLong) { int time = 0; System.out.println("At the beginning, we have:"); while (time <= timeLong) { System.out.print(time + ": "); x.divide(time); y.divide(time); try { y.beenEaten(x.needToEat(time)); } catch (NoMoreYException e) { System.out.println("No more Ys, they have been eaten up. " + "Meanwhile, there are " + x.amount() + " Xs."); return; } time += 30; System.out.println(x.amount() + ", " + y.amount()); } } /** * Test bacterium. */ public static void main(String[] args) { TestBacterium t1 = new TestBacterium(10, 89); t1.startTick(3600); TestBacterium t2 = new TestBacterium(10, 90); t2.startTick(3600); } }
NoMoreYException类
package bacterium2; public class NoMoreYException extends Exception { }
运行程序,输出如下。
Y初始数量为89: At the beginning, we have: 0: 10, 89 30: 10, 79 60: 10, 79 …… 2310: 40960, 8192 2340: 81920, 8192 2370: No more Ys, they have been eaten up. Meanwhile, there are 81920 Xs. Y初始数量为90: At the beginning, we have: 0: 10, 90 30: 10, 80 60: 10, 80 90: 10, 70 …… 3540: 5242880, 52428800 3570: 5242880, 47185920 3600: 10485760, 94371840
到此还没有结束……
这个问题本身比较简单,但它表现出的一个现象却非常不简单:初始条件的一点细微差别,可能导致结果的巨大差别。
Y的初始数量分别为89和90,相差非常小(小于1.2%),但结果却是前者Y在2370秒时被吃完,而后者Y最终达到了接近1亿的数量。
如果一个系统的演变过程对初态非常敏感,就称它为混沌系统。一门新学科,即混沌学(Chaos),专门研究这种混沌运动。
最初发现这一现象的是美国麻省理工学院的气象学家洛伦兹(Lorenz)。为了预报天气,他用计算机求解仿真地球大气的13个方程式,意图是利用计算机的高速运算来提高长期天气预报的准确性。1963年的一次试验中,为了更细致地考察结果,他把一个中间解0.506取出,提高精度到0.506127再送回。而当他到咖啡馆喝了杯咖啡以后回来再看时却大吃一惊:本来很小的差异,结果却偏离了十万八千里!再次验算发现计算机并没有毛病。洛伦兹发现,由于误差会以指数形式增长,在这种情况下,一个微小的误差随着不断推移造成了巨大的后果。他于是认定这为“对初始值的极端不稳定性”。
随后他在一篇提交纽约科学院的论文中分析了这个效应:“如果这个理论被证明正确,一只海鸥扇动翅膀足以永远改变天气变化。”在以后的演讲和论文中他用了更加有诗意的蝴蝶,因此这种现象又被称为“蝴蝶效应”。对于蝴蝶效应最常见的阐述是:“一只蝴蝶在巴西轻拍翅膀,可以导致一个月后德克萨斯州的一场龙卷风。”
这个发现非同小可,以致当时的科学家都不理解,几家科学杂志也都拒登他的文章,认为“违背常理”——相近的初值代入确定的方程,结果也应相近才对,怎么会偏离如此之大呢!
混沌的本质是系统的长期行为对初始条件的敏感性,是由系统内部的非线性因素引起的。线性,指量与量之间按比例、成直线的关系,在空间和时间上代表规则和光滑的运动;而非线性则指不按比例、不成直线的关系,代表不规则的运动和突变。例如两只眼睛的视敏度是一只眼睛的几倍?按线性来推测结论是2倍,但事实是6-10倍,这就是非线性。1+1并不等于2。
混沌不是偶然的、个别的事件,而是普遍存在于宇宙间各种各样的宏观及微观系统的。混沌也不是独立存在的科学,它与其它各门科学互相促进、互相依靠,由此派生出许多交叉学科,如混沌气象学、混沌经济学、混沌数学等。
有观点认为,混沌应属于二十世纪三大科学之一。相对论排除了绝对时空观的牛顿幻觉,量子论排除了可控测量过程中的牛顿迷梦,混沌则排除了拉普拉斯可预见性的狂想。混沌理论将开创科学思想上又一次新的革命。混沌学说将用一个不那么可预言的宇宙来取代牛顿、爱因斯坦的有序宇宙,混沌学者认为传统的时钟宇宙与真实世界毫不相关。