2005年7月17日星期日

求大数的阶乘

昨天看到博客园的一篇文章《10000的阶乘的算法(大数的阶乘)》,自己也想了一下,写了一个 C# 版的。程序也比原文的要简单。

原文中,数组大小 M = log10^1+log10^2+log10^3...+log10^n,好像不对。我觉得应该是 M = log10(1) + log10(2) + ... + log10(n),log10(1) 表示以10为底数、1为真数的对数。可能我们表达的是一个意思,只是写法不同而已(不过我还是觉得10^3 = 1000,log10^3 = 3,这样明显不对嘛)。

程序:

using System;

namespace Factorial
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
int n, M, carry = 0, t1;
double t2 = 0;
bool display = false;
int[] result;

Console.Write("Input the number you want to factorial: ");
n = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("");

for (int i = 1; i <= n; i++)
t2 += Math.Log(i, 10);
M = (int)Math.Ceiling(t2);

result = new int[M];
result[0] = 1;

for (int i = 1; i <= n; i++)
for (int j = 0; j < M; j++)
{
t1 = result[j] * i + carry;
result[j] = t1 % 10;
carry = (t1 - result[j]) / 10;
}

Console.WriteLine("The result is: ");
for (int i = M - 1; i >= 0; i--)
{
if (result[i] != 0 && !display)
display = true;
if (display)
Console.Write(result[i]);
}

Console.ReadLine();
}
}
}

用 Windows XP 自带的计算器验算了一下,1000! 应该是没问题的,但算 10000! 确实算不出来,要等很久。原文的那个程序也是要等很久,而 Windows 自带计算器只等了 1 秒钟左右。我想,要不然是 Calc 省略了后面的位数,要不然是 Calc 有更好的算法。

小程序,轻松一下。:-)

平淡的日子

最近广州还是很热,天一热,人也就懒了,每天的日子也过得很有规律,无非就是写写程序,看看书,订订外卖,睡睡觉。要说因此得到了什么,那只能说,知道了什么样的生活叫做无所事事,叫做没有动力。:(

明天托福班就开课了,总算是一个改变的契机吧,至少能给自己一个出门的理由。人是很容易被麻痹的,除非自己不断提醒自己,要改变,要像自己希望的方向改变。

2005年7月7日星期四

网络游戏的一点开发经验

以前从没接触过网络游戏方面的编写。前段时间因为课程原因,和班里同学组队写了一个网络游戏,虽然功能上比较简陋,但是麻雀虽小,五脏俱全,网络游戏应该有的几个基本元素都有了,也算是在网络编程上的一次新的尝试了吧。

游戏是用 Java 写的,原因是,我们学那本教材的示例是用 Java 写的。从产生最初的设想,到最后的完成总共是一个半月左右。因为是组队编写,所以在分工合作上就必须十分注意,而且一个月内要完成一个具有界面、网络通讯、游戏逻辑等等内容的软件对于一个没有经验的人来说工作量太大了些。

我们采用的方法是分工-整合,即先通过分析把软件分割成几个技术块,分给组员去研究,等他们把自己那块研究得很透彻了以后,就把自己在那一块的经验、需要注意的地方、一个自己写的典型的示例交给一个整合者。整合者需要较高的程序开发能力,至少要对各个技术块都要有一点了解,并且能够很快从各研究者那里学到东西,然后把各个部分整合起来,完成整个软件。

实际当中,我们分割的技术块有以下几个:

1. 核心算法、逻辑(同时也是整合者);

2. 界面设计;

3. AWT + Swing;

4. 网络通讯(组播 + 流式 Socket)

5. 安装和分发。

非常有幸的,我担任核心算法的那一块,从自己,也从别人那里学到了很多。

在编写过程中主要遇到了以下几个问题:

1. 各个客户端如何互相识别;

2. 非原子对象如何通过网络传输;

3. 组播的可靠性;

4. 逻辑部分的架构怎么设计,才能保证简洁、有效、少出错。

相应的每个问题的最后解决方案是:

1. 我们考虑了是否使用服务器作为中间人。一种情况就是各个客户端就通过组播传递一个只属于自己的 ID。但是因为组播机制的问题,我们(好像)不能仅仅经由组播组得知组里有多少成员,更不可能收到类似“有新的成员加入组”的消息。经过考虑,我们还是决定使用客户端-服务器模型,有服务器分发 ID,这样,服务器就能分担很多原本在客户端的开销了(特别是使用多线程以后)。

2. 很明显的,用序列化。为了这个,我和一个同学争论了一个晚上,他想用类似网页表单的形式,最后终于说服了他(有现成的技术干嘛不用)。

3. 通过最后的测试,我发现,组播的时序是一个很麻烦的问题,特别是在还有网络延迟的情况。在游戏中,3 个客户端在接收(并发送),1 个客户端在发送(并接收),我怎么保证客户端 A 他先收到客户端 B 接收后发送的消息,还是客户端 C 直接发送的消息?如何保证自己发送的消息自己能最快地接收到?实际情况中,几种可能性都是存在的,也都发生过。我没有找到什么很好的解决办法,只能是增加条件判断。

4. 架构,最难办的东西。就这么一个小游戏,要把它的规则用程序描述出来也是不容易的。更难的是在怎样有效、正确的传递结果,特别是在上面提到的不太可靠的环境下。为了赶时间,我没有花很多时间在设计架构上,还是采用了沿时间的线性编程。事实证明,这简直就是地狱,你将需要非常多的 if, else 放在各个关键点,很多时候为了解决一个匪夷所思的 Bug,又要添加 AND 或者 OR。到最后,逻辑部分变得很冗繁,很复杂,即使有 Bug 也很难找到。这也算是对我偷懒的惩罚吧。

其实对于架构,也想到一种方法,时间表。事前为每一个客户端制作一份时间表,时间表中记录了客户端每一步应该做的事情,这样每个客户端就不需要关心其他客户端发生的步骤,只需要将其他客户端发送的数据接收并正确显示即可。制作和使用时间表并不容易,但是对于复杂流程来说,这会是一个比较好的解决方案,从逻辑上来说,这就是把整个过程式的流程分割了并分发给每个客户端。每个客户端的对应时间表是在一份基本时间表加上以客户端的本地的独特数据(如 ID)作为基础的变化后生成的。我想在以后哪次写类似的软件时有可能会用到这种技术。

另外,以前都是用 C++,C# 的,第一次用 Java,感觉 .NET 确实是从 Java 中汲取了很多好的思想、细节,摒弃了很多麻烦、不实用的东西。两者在语法结构上都很相似,但感觉 C# 更像 C++ 一些。(而正是这许多些微的不同,形成了很多各式各样的争论。)个人来说并不觉得 Java 就比 .NET 差或者落后,只是比较不习惯。还是要看在什么领域里面应用,有些适合 J ,有些时候 N,没有一定的。不过,对于 Java 的图形界面设计,我是深恶痛绝。要想用 AWT 设计出像 .NET 一样整洁清新的“一般”窗体是多么困难的事啊!

还有很多感想,一下子也想不出。以后再说吧。

2005年6月3日星期五

古尔德的复调风格

再听古尔德的贝多芬钢奏,慢慢发现了古尔德演奏这部作品之所以和别的钢琴家那么不同的原因。

稍微注意一下他左手和右手的处理,可以发现在很多地方他的左右手力度几乎相同,即使在那些突出右手主弦律的地方也是如此。这种处理方法在复调音乐里是很基本的,因为复调的左右手根本没有什么分别。古尔德将这种方法用到了贝多芬里面,感觉就很不同了。虽然乍一想这样做很疯狂,但事实证明效果不错 lol !

除了左右手的处理,古尔德在速度上的掌握也充满了复调音乐的特点。在一首曲子里面,他极少有节奏速度的改变,而一般很多人对贝多芬都强调流畅,速度上会比较自由。这个特点也很明显的有复调感,好像古尔德弹贝多芬钢奏就像是在弹赋格的艺术,只是音符有所不同而已。另外,古尔德对自己喜欢的曲子一般都处理得很慢,不喜欢的就极速拉过去,这又是他个人风格的体现了。从海顿奏鸣曲和别的曲子不同的录音效果来看,古尔德应该是对这三首重录过的,这应该可以解释为什么三首的慢板乐章他会处理得那么慢了。

其实虽然古尔德这样演奏贝多芬就好像杀牛用马刀,但实际上我仍然很喜欢他的演奏,这是一种完全不同的方式,是另一种可爱,不可多得的。

2005年5月17日星期二

肖邦

今天学校的广播结束时,放起了肖邦的钢奏。那时我正准备出门,突然起了想要重听一下肖邦的念头。刚刚当夜曲(这套盘是那套鲁宾斯坦演奏的,夜曲是第一张盘上的)响起的时候,旧时的那些记忆又立刻重现了。这还是高中时的肖邦,还是和 Alex 在音乐课上听到的肖邦,还是三楼老家里,晚上准备高考冲刺时的夜曲。

论作曲技巧,肖邦远不如巴赫;论艺术手法,非贝多芬莫属,但肖邦确实是不可替代的,即使那么长时间没有去碰过那一套老碟,记忆中永远还是为他留着一席空间。肖邦的音乐并不是一成不变的忧伤,他有一种魔力,能让我总是去想而非去思考。如果要问到底在想什么,我只能说,就像很多涉及到艺术和内心的东西一样,那是难以言传的;而正为此,体会又更加地强烈。总而言之,耳中的音乐似乎和 5 年前的音乐是一样的,但它在自己内心中的 Image 又有了很大的变化。毕竟,人就是在变化。

晚上下了一场雨。回宿舍的时候,又路过湖边的那棵树。耳中的是夜曲,眼前是朦朦胧胧的北湖,鼻中是湿润清新的空气,加上头上的一轮半遮半掩的月亮,我觉得这棵树真的是那么地孤傲和威严,又那么地令人感觉和蔼可亲。一种自私的念头告诉我,我是在拿自己和它作比较。我希望自己能具有它的这些特质。夜色是美的,音乐也是宁静的。

回到宿舍,就像突然进入了另一个世界,一个陌生的世界。人,又总归得生活在陌生的世界里。

2005年5月14日星期六

再谈开源

我觉得开源在很多时候并不是旨在把自己写的代码公布出来,让大家学习、修改,因为真正的大型软件的代码也不是一两个人、每个人都能看懂的,那需要对软件构架有足够的了解。而那些真正又能够从这些开放的、有用的源代码中受益的、牟利的也只有大型的软件公司,换句话说,就是那些制作软件并公布源代码的公司的竞争对手们。我想这就是大型软件一般都不开源的原因,毕竟,源代码里面可以包含太多太多的东西。

但至少,开源项目标榜了一个概念,就是我的这一行绝不是由我一个人来解决所有问题,绝不是由我来垄断,我只是为这一行提供了一个可能的解决方案,用户要用哪个是由用户根据自己的实际情况来决定。正如我原来说过的,这样做确实不可能产生一个十分强大的软件或系统,能够平衡地应付所有已经被发现的问题,甚至会产生一台计算机为了解决不同问题需要安装几套开源软件。但是,如果出现了新的情况,新的问题,开源软件确实能够更快地做出调整、改变。而像 Windows 那样的大块头,要想翻一个身、挪一下腿,决不是一件容易的事情(这就像自然界中蚂蚁和大象比喻一样)。

其实我也很清楚,大家一般愿意选择商业软件的原因,除了为了有技术支持等等保证外,其实还有虚荣心。打个比方,你现在并不知道有 IE 和 Firefox 这两个浏览器,我现在告诉你,IE 是微软做的,Firefox 是 Mozilla 的,你会安装哪一个?我们可以假设你用的就是 Windows,因为看在 Windows 的市场占有率的份上这个假设并非不合理。我想首先你可能会想一下 Mozilla 是什么玩意儿,但绝不会去想微软是什么玩意儿。然后,草率的你(我们假设,只是假设)会毅然决定“用 IE 吧”,原因也不是说 Mozilla 不出名,而是,Windows 是微软的,干嘛又要来一个什么 Mozilla 的软件呢?清一色的微软不是更爽吗?这样,Firefox 就出局了,IE 的霸主地位也就建立了。

我想如果把上面的主角之一 Firefox 换成 Netscape,就重演了当年的那一幕,人们会说,这就是捆绑的力量。我不是说 IE 不好,因为 IE 也在进步,如果拿 IE 3.0 和 Firefox 来让你选,出局的一定是 IE。也正是拿 IE 6.0 来比,虽然在有些方面 IE 不如 Firefox,不如 Netscape,但和“清一色”的快感、安全感、满足感相比,这些不足也是完全可以接受的。虽然不太好听,但是大多数人在选择软件的时候都是“草率的”,包括我。有些人可能根本没有试用过某一款软件,就在某个论坛里说这个软件不如某某软件,而原因仅仅是他没有听过这个软件的名字和制作公司的名字。

无论如何,我只是想说,开源和不开源确实是各有优点的,各有各自适用的领域,任何事情都不是一两天、一两年就能看出端倪的,你我都不能保证在十年二十年以后,我们大家的电脑里是不是都装着 Linux,或者 xxxnux,对不对?

2005年4月23日星期六

软件大赛

去年 12 月,决定参加学校的软件设计大赛,今天初赛终于结束了。一个简单的 3D 引擎自然没有奢望要进复赛,但在这整个大赛的过程中思考了很多。

游戏开发。当初决定做的并不是 3D 引擎,而是用 DirectX 做一个 3D 的记事本,后来才转而去做 C# + Managed DirectX 的 3D 游戏引擎框架。一个 3D 游戏需要的是大量的综合的技术,你需要对图形学有很深的了解,对图形硬件有系统的知识,你需要对操作系统的相关接口比较熟悉,你还要考虑声音、用户输入、网络通讯、美工、兼容性……这一切不是一个人能做得完的,必须选择其中 1、2 个深入地研究。而对于我来说,更擅长的还是抽象、对象、算法和逻辑,那么,是不是说游戏开发对我来说并不合适呢?是不是说,如果我决定在图形这方面更深入地了解下去,CAD 对我会是更好的选择呢?

.NET 的位置。4 月份的《程序员》在很大程度上改变了我对 .NET 和 Java 以及开源的态度,那时也正是我写引擎进入最关键阶段的时候。建议有机会的话还是去看看那篇《微软:令专家失望的 .NET》。虽然我并没有因为这篇文章改变多少对微软软件的信赖,但着实让我对开源有了一些更多的认识。这次软件大赛结束后,遇到一位已经毕业的师兄,听他说对 J2EE 有些专,也就和他讨论了一些 Java 和开源。他说,开源最大的优势在于这个群体的庞大,它的庞大使它能满足任何的市场需求。大型服务器需要相关软件,就有人做服务器系统;软件开发需要相关软件,就有人做 IDE,做插件;甚至他们电信要软件,也可以在网上找到相关的软件,改一下拿来用。这些,微软一个公司是做不到的。微软更关心中小型企业的市场,如果你现在要在服务器上传输一个 40G 的文件,你能叫微软来帮你解决么?总而言之,微软是做出了软件让大家来适应它,开源是大家提出要求,它来实现。

我今后要走的路。真是感到矛盾,一方面,我对游戏、图形编程很感兴趣,用手指创造动画特效的感觉是无可替代的,另一方面,我又对更加底层、抽象的编程绝对热爱,那是一种数学的美,智慧的美,成就的美。当然,现在决定以后要专攻具体哪方面的研究似乎还为时太早,就像 Alex 说的,本科应该是广阔视野,打基础的时间。也许,这种矛盾也是一种好的现象,至少,它表明我对计算机仍然具有热情,和 10 年前相比只增无减的热请吧。

另外,我觉得我是一个这样的人,平时没有编程“任务”的时候,真的是一点程序都不想去碰,那种“又要动脑筋苦苦思索”的潜意识会阻止我去打开 Visual Studio。但一旦我不得不动手开始编一个程序,一旦我已经陷入这个程序了,那我会不吃不喝不睡不休得完成它。似乎这样对身体有很大的坏处,但,我有什么办法呢?江山易改,本性难移,青山不改,绿水长流。

2005年4月22日星期五

古尔德的贝多芬

这段时间一直在听古尔德演奏的贝多芬的钢奏,特别是前期的几首。很明显能听出来,前期的那几首古尔德是在后来重录过的,音质上和大部分后期作品很大不同。不仅如此,从他的演奏中也可以看出来他个人对前期奏鸣曲的喜爱:一个字,慢。如我们所知,古尔德对不喜欢的东西从来就能多快就多快地飞过去,而中意的那些曲子就慢慢的蕴,让自己陶醉进去。当然,我们是从中得益了。

前三首奏鸣曲古尔德演奏得确实太可爱了,除了可爱,我也找不到其他的词来形容了(特别是第三的第二乐章,那么的慢,但却丝毫不让人感到拖沓)。给我的感觉就是:我们似乎回到了一个梦幻般的童年,没有忧愁,没有顾虑,有的只是在那个梦幻里面应该有的。这种感觉,有时我也能在勃拉姆斯和肖邦里面找到,而在这里,在古尔德里面,我也找到了贝多芬纯洁、童真、浪漫的一面。我丝毫不觉得第一奏鸣曲的作曲技法有多幼稚,我只是认为,在这里没有,也不该有任何其他多余的东西了,它已经恰到好处了。说它像莫扎特,我觉得只有一个形似,骨子里面贝多芬永远是一个直率的人,不像莫扎特让人有那么多猜测。

写到这里,我想起我这几个星期的周六都是一个人去外面吃饭,吃到很晚,然后慢慢走回学校,在没有路灯的湖边一遍又一遍地走,听古尔德的贝多芬,一种“收缩”的感觉在那个时候那么的强烈,我好像是被孤独重重包围了,又好像不是。在那个时候,平时所有的朋友同学都在这个世界存在着,做着他们自己的事情,而在我的世界里面,他们又全都不在,没有任何一个别人和我一同感受我的感受。我似乎骄傲地享受这一特权,但实际上这只是自己给自己的特权罢了。我特别喜欢湖边的一棵树,很高很老的一棵树,没有什么特别的原因,或许它的形状在夜里让我感觉它永远都会像它现在一样。我想,如果十年二十年以后有一天我还能回到这里,我会记起去看它,就像对待老朋友一样,一个在患难中唯一给我帮助的朋友。

2005年4月7日星期四

我的父亲 (3)

父亲的死对我的影响是很深的,最直接的影响是:我对女性的态度。

首先,是对我的母亲。简而言之,是强烈的俄迪浦斯情结。父亲的死使我成为了家中唯一的男性,在这种环境下,我能够感到我自己好像是在替代父亲的位置,亦即成为自己的父亲和母亲的丈夫,而这在我潜意识中是强烈反抗的,我认为这是不对的。所以,我并不是对母亲更加亲切和更加孝顺,而是在无意识中疏远她。另一方面,我知道我是母亲的儿子,她是我的母亲,我应该去爱她,这又把我带回俄迪浦斯情结的边缘,因此,我一直在矛盾中苦苦寻找平衡。

然后,是对同龄的那些女孩们。对母亲的这种心理矛盾使我非常急于为自己找到一个安全的立足点,我希望我能够回到正轨上来,而最好的办法就是为自己找一个合情合理的爱人。这种感情内在的表现是对女性的强烈的渴望,而外在的表现却恰恰相反,即对女性的假意的冷漠。为什么?因为过分的表露对女性的渴望使我害怕别人(主要是女性)知道我的秘密,知道我热烈的原因,也就是知道我的俄迪浦斯情结,而这个情结是我连自己都千方百计避免去面对的。

我相信,这种情结在我有生之年都一直会或多或少地影响我。在父亲死后不久,我曾经认为,没有父亲其实并不会有多大的改变,因为还有母亲养活我,我还并不是孤儿,并不会因此改变生活环境,你看,不是一切照旧么?不是没有人知道我的秘密么,只要我把秘密守得够紧?现在我知道,我从他死去的那一刻就已经被决定了,我也再不可能像那些一般人一样了,这是无论我多么努力,靠自己的力量都无法改变了的。我无法完全理解那些一般人的某些思想,就像他们无法理解我的一样。这里面呢,也无所谓谁更占便宜,谁更优越一些,只要自己能面对事实,那么一切都是公平的。我现在很坦然地接受这一切,并不埋怨任何人和事,一切的一切,谁都没有错,谁都不可能有错,因为谁都没有权利在只有上帝才有权利决定的事里面作自己的主观判断,是不是?

2005年2月21日星期一

未来的体验是什么样的?

这几天看了《程序员》的关于 RIA 的专题,还是有些想法。说实话,每次捧着那本书的时候,都会犹豫一下“买不买”。这次,是 RIA 让我打消了犹豫。

因为我对 DirectX 很感兴趣,也相信 3D 的用户体验在不久的未来一定会占据普通用户的市场,所以很早就想如果能在网页中大量的嵌入 D3D 的程序,那么网络带给用户的比现在会多很多很多。比之 Flash(至少,这是目前 RIA 提倡的两大阵营中的一个),DX 优在它的 3D,因为好的 3D 程序不言而喻的能带给用户更丰富的体验,而它劣也劣在它的 3D,因为同等次的 3D 程序的开发难度肯定比 2D 的要难很多,这就会导致开发时间、成本,以致成品质量上的不足。同时,其庞大的体积也使其不可能在现在的互联网环境广泛、快速的传播。

但是,随着网络硬件的不断发展,体积问题将越来越不成为问题。而开发复杂的问题也应该会随着 3D 程序的框架化而得到最大限度的降低(同时,成本问题也会相应解决),毕竟,只有人们越来越多的关注某一种技术,这种技术才会得到长足的进步,这里的框架化也是以此为前提的。想一想,哪一天,一个普普通通的程序员都能用积木的方法“拼”出一个他自己的华里的 3D 程序,那么那时流行于网络的二进制代码带给我们的会是什么样的啊!

所以,比较一下当前的两大 RIA 解决方案,我更倾向于微软的 Avalon。当然,技术应该服务于需求,未来的一切最终还是由用户自己决定的。我们,应该预测未来。