随笔 - 53, 文章 - 0, 评论 - 3, 引用 - 0
数据加载中……

2009年1月13日

java.sql.BatchUpdateException: IO Error: Connection reset

during analysis of "IO Error: Connection reset", many articles mentioned that it could be caused by java security code (accessing /dev/random) used in JDBC connection. However it is not the root cause in my case. In my environment, Java already use /dev/urandom. 1. $JAVA_HOME/jre/lib/security/java.security securerandom.source=file:/dev/./urandom 2. check with strace. only -Djava.security.egd=file:/dev/../dev/urandom will trigger system call (read on /dev/urandom) all other other path format like below are OK. -Djava.security.egd=file:/dev/./urandom -Djava.security.egd=file:///dev/urandom 3. Keep checking the retropy size, I have never seen it is exhaused. while [ 1 ]; do cat /proc/sys/kernel/random/entropy_avail sleep 1 done usually the avail is in the range from 1000 to 3000. so far, there is no clue about the root cause of "IO Error: Connection reset".

posted @ 2017-02-20 09:28 InPractice 阅读(1293) | 评论 (0)编辑 收藏

Lessons learned - Oracle GI and Database Installation on SUSE 12

I encountered many issue during installation of Oracle Grid Infrastructure(GI) and Database; with the help of ariticle and documents found through Google search engine, I finally made it. for records, here is the details issues encountered and solutions applied. Major issues were encountered during GI installation. Pre-installation tasks. Issue 1: swapspace is not big enough; (1.3.1 Verify System Requirements) grep MemTotal /proc/meminfo 264G grep SwapTotal /proc/meminfo 2G during OS installation, I take default option and swap space is only 2G. Oracle recommend to have more than 16G swap space in case of more that 32G RAM. dd if=/dev/zero of=/home/swapfile bs=1024 count=33554432 33554432+0 records in 33554432+0 records out 34359738368 bytes (34 GB) copied mkswap /home/swapfile mkswap /home/swapfile chmod 0600 /home/swapfile lessons learned: setup swap space properly according to DB requirement when installing OS. Issue 2: cannot find oracleasm-kmp-default from Oracle site. (1.3.6 Prepare Storage for Oracle Automatic Storage Management) install oracleasmlib and oracleasm-support is easy, just download them from Oracle and install them; Originally oracleasm kernel is provided by Oracle, but now I cannot find it from Oracle; finally I realized that oracleasm kernel is now provided by OS vendor; In my case, it should be installed from SUSE disk; a. to get its name oracleasm-kmp-default zypper se oracle b. map dvd and install zypper in oracleasm-kmp-default rpm -qa|grep oracleasm oracleasm-kmp-default-2.0.8_k3.12.49_11-3.20.x86_64 oracleasm-support-2.1.8-1.SLE12.x86_64 oracleasmlib-2.0.12-1.SLE12.x86_64 asm configure -i asm createdisk DATA /dev/<...> asm listdisks --DATA ls /dev/oracleasm/disks Installation tasks: Issue 3: always failed due to user equivalence check after starting installer OUI with user oracle. however if I manully check with runcluvfy, no issue found at all. ./runcluvfy.sh stage -pre crsinst -n , -verbose I worked around it by using another user to replace user oracle. but it triggered next issue. Issue 4: cannot see ASM disks in OUI. no matter how I change the disk dicovery path. the disk list is empty. but I can find disk manully. /usr/sbin/oracleasm-discover 'ORCL:*' Discovered disk: ORCL:DATA Root cause is that the ASM is configured and created with user oracle. and I aming installing GI with different user other than oracle; so I cannot see the Disk created. change owner of disk device file solved the issue. ls /dev/oracleasm/disks chown /dev/oracleasm/disks -R Issue 5: root.sh execution failed. Failed to create keys in the OLR, rc = 127, Message: clscfg.bin: error while loading shared libraries: libcap.so.1: cannot open shared object file: No such file or directory fixed the issue with command below: zypper in libcap1 ohasd failed to start Failed to start the Clusterware. Last 20 lines of the alert log follow: 2016-07-24 23:10:28.502: [client(1119)]CRS-2101:The OLR was formatted using version 3. I found a good document from SUSE, Oracle RAC 11.2.0.4.0 on SUSE Linux Enterprise Server 12 - x86_64, it make it clear that SUSE 12 is supported by Oracle GI 11.2.0.4, it also mentioned Patch 18370031. "During the Oracle Grid Infrastructure installation, you must apply patch 18370031 before configuring the software that is installed. " The patch 18370031 is actually mentioned in "Oracle quick installation guide on Linux", but not mentioned in "Oracle quick installation guide on Linux". I majored followed up with later one and missed Patch 18370031. issue disappeared after I installed the patch 18370031. ./OPatch/opatch napply -oh -local /18370031 Errors in file : ORA-27091: unable to queue I/O ORA-15081: failed to submit an I/O operation to a disk ORA-06512: at line 4 solved by change owner of disk DATA related file ls -l /dev/oracleasm/iid chown on folder /dev/oracleasm/iid and some .* hidden file. Issue during DB installation Issue 6: report error: in invoking target 'agent nmhs' vi $ORACLE_HOME/sysman/lib/ins_emagent.mk Search for the line $(MK_EMAGENT_NMECTL) Change it to: $(MK_EMAGENT_NMECTL) -lnnz11 refer to https://community.oracle.com/thread/1093616?tstart=0

posted @ 2016-07-28 16:55 InPractice 阅读(250) | 评论 (0)编辑 收藏

卸载Ubuntu需要注意的地方

很多年前装了UbuntuWindows的双系统,最近因为有了专门的电脑来装Ubuntu,所以把原先电脑上的Ubuntu卸载了,结果系统不能引导了。因为GRUB的原理是控制权从MBRUbuntu系统盘,然后Ubuntu系统盘再提供对windows的引导。现在Ubuntu系统被卸载了。这个启动的链条也就断了。

这个问题本身不难解决,借了一个
Windows安装盘,恢复一下MBR即可。但是这个需要windows系统的Administrator密码。而我的系统不是我装的,我根本不知道这个密码。

有的帖子提到破解
Administrator密码,试了一下,觉得太麻烦了。因为电脑上有数据,也不能重装。 

最后的解决方案是在原先的
Ubuntu分区上安装一个新的Windows。这样变成了windows的双系统。安装完重启之后可以进入任何一个系统(新的或者旧的Windows)。安装的过程中MBR被自动更新了。再下来就改一下老系统的Administrator密码,删除掉多于的Windows新系统即可。

posted @ 2011-04-11 18:19 InPractice 阅读(631) | 评论 (1)编辑 收藏

使用GMail的困惑

用Gmail的时候不小心点了"存档"按钮,一封重要的邮件就此消失了好几天,今天才机缘巧合找到。

在网络上查到的解释是:
        存档会将邮件从收件箱移至所有邮件,这样您不必删除邮件就可以整理收件箱。

难以理解,坦率地说,这个功能对我来说是徒增烦恼。看来任何工具都需要你去适应,磨合。

posted @ 2011-02-11 11:02 InPractice 阅读(240) | 评论 (0)编辑 收藏

华容道游戏的解决

最近买了一个叫做“华容道”的玩具给儿子晚。这个游戏虽然号称是中国四大古典智力游戏之一。其实不过百年历史,而且是从国外引进的。不过本地化做得非常好,也算是创造性地吸收国外文明。

手工解决这个游戏有点难度,当然已经有人给出了解法;不过我还是自己用编程的方式解决了一遍。发现自己在这方面的编程还是比较弱。大部分时间花在了调试上。

刚开始是用的深度优先搜索。大致知道了答案应该长什么样。后来改进为广度优先搜索,得到了最优的解法。还有一个就是原先只考虑每次最多移动一格。后来发现传统的定义是一个块的所有连续移动都算作一步。相应地修改了实现算法。

最难的是做界面。为了调试,随便写了个Applet。但是给我儿子玩,就觉得拿不出手了。



posted @ 2010-08-16 13:49 InPractice 阅读(315) | 评论 (0)编辑 收藏

Meta Information

Just use this blog to share some meta information.


  
git://github.com/ueddieu/mmix.git
http://github.com/ueddieu/mmix.git

posted @ 2010-06-05 06:44 InPractice 阅读(182) | 评论 (0)编辑 收藏

Notes on Gentoo Installation

After two weeks' struggle, I have successfully installed Gentoo, a popular GNU/Linux Distribution. For Records, the obstacles I encountered are listed below. (but I can not remember the solution exactly)

0. failed to emerge gpm when I install the links package. If I recall correctly, it is resolved by install gpm manually

1. I encounter issue when I install glib 2.22.5. no update-desktop-database. which is in dev-util/desktop-file-utils. When I try to emerge it, there is a circular dependency on glib. no solution and I forget How I resolve the problem.

2. later after I install glib, with ~amd64 keyword I can install gpm-1.20.6, but it conflicts with the manually inatalled gpm. I remove the conflicted file and emerge successfully.

3. Failed to emerge tiff. edit packages.keywords to add the following. / ~amd64 I am able to use latest tiff in beta-version, which is unstable and masked out.

4. later atk-1.28.0 failed to emerge. edit /etc/make.conf with the following. FEATURES="-stricter". then emerge successfully with only some complain. with out this seting. the warining from GCC will cause that emerge fail.

5. when I run emerge --update system actually gcc will be upgraded from 4.3.4 to 4.4.3. but it failed because of compilation warning, again. add "-stricter" into Features variable in /etc/make.conf work around it.


6. The installation takes a long time, the KDE itself take more than 10 hours. There is still a lot of improvement space! Anyway, it is nice to be able to use it daily.

posted @ 2010-06-03 16:33 InPractice 阅读(330) | 评论 (0)编辑 收藏

为SVN客户端设置Proxy

在C:\Documents and Settings\<user_name>\Application Data\Subversion\servers文件中加入
all=*.*

[all]
http-proxy-host = ***.**.com
http-proxy-port = 8080

这里的all映射到所有的Server。

网络环境的复杂给我们的工作带来了一些影响。就拿Proxy的设置来说,本来理想的情况是在全局做一个设置就可以了,但是事实上我们要为每个程序做设置,而且语法还不一样。

posted @ 2010-04-21 17:00 InPractice 阅读(757) | 评论 (0)编辑 收藏

小心一些太过智能的工具,比如Word。

今天从word文档中拷贝脚本到命令行执行。没有想到的是Word自动加入了空格,导致执行失败。具体如下。
call ttGridCreate('$TT_GRID');
被word变成了
call ttGridCreate(' $TT_GRID');
这个空格可不容易被发现,尤其你不是脚本作者的时候。提高警惕!

posted @ 2010-04-13 16:13 InPractice 阅读(236) | 评论 (0)编辑 收藏

访问Java对象属性的性能模型。

今天做了一个简单的性能测试。比较访问Java对象属性的各种方法的性能差异。
1. 直接访问对象的属性。
2. 用方法访问对象的属性。
3. 用Map来存储和访问。
4. 反射-Field 访问。
5. 反射-Method访问。

重复100次,结果如下(单位为纳秒)。
 * 100 field access, 14,806<br/>
 * 100 method access, 20,393<br/>
 * 100 map access, 66,489<br/>
 * 100 reflection field access, 620,190<br/>
 * 100 reflection method access, 1,832,356<br/>
重复100000次,结果如下(单位为纳秒)。
 *100000 field access, 2,938,362
 *100000 method access, 3,039,772
 *100000 map access, 10,784,052
 *100000 reflection field access, 144,489,034
 *100000 reflection method access, 37,525,719 <br/>
 
由结果可见:
1。getter/setter 的性能已经接近直接属性访问(大约慢50%),没有必要担心getter/setter的性能而采用直接属性访问。
2。用Map代替POJO的代价大约是比getter/setter慢三倍。
3。反射访问比getter/setter慢50到150倍。慎用。追求动态性的时候也要注意不菲的性能代价。
4。注意重复次数增加到100000次,方法访问和属性访问的差距缩小;更有意思的是,反射的Method访问比Field访问快四倍。这主要是JIT的作用。

该测试结果和原先的猜想基本符合。但是性能评估很容易得到片面的结论,如果有错误的地方,请大家不吝指正。谢谢。

posted @ 2010-04-09 15:57 InPractice 阅读(331) | 评论 (0)编辑 收藏

Tomcat Source Code Reading

0. I am reading the source code of Tomcat 6.0.26. To pay off the effort,
I documents some notes for record. Thanks for the articles about Tomcat
source code, especially the book <<How Tomcat works>>.

1. They are two concepts about server, one is called Server, which
is for managing the Tomcat (start and stop); another is called Connector,
which is the server to serve the application request. they are on the different
ports. The server.xml clearly show the difference.

<Server port="8005" shutdown="SHUTDOWN">
  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

although the server is the top level element, logically it should not be.
Actually in code, Bootstrap starts the service first, which
in turn start the Server and server's services.

2. My focus in on Connector part. I care how the request is services by the
Tomcat. Here are some key classes.

Connector --> ProtocolHandler (HttpProtocol
                        and AjpProtocol)                       --> JIoEndPoint
                                                                           --> Handler(Http11ConnectionHandler
                                                                           and AjpConnectionHandler)
                                                  
                                                  
3. Connector is most obervious class, but the entry point is not here.
The sequence is like this.

Connector.Acceptor.run()
--> JioEndPoint.processSocke(Socket socket)
    -->SockeProcess.run()
        -->Http11ConnectorHandler.process(Socket socket)
            -->Http11Processor.process(Socket socket)
                -->CoyoteAdapter.service(Request req, Response res)       

The core logic is in method Http11Processor.process(Socket socket)                                                  

CoyoteAdapter.service(Request req, Response res) bridges between Connector module and Container module.

Any comments are welcome. I may continue the source code reading and dig deeper into it if time permit.


posted @ 2010-03-30 17:11 InPractice 阅读(604) | 评论 (0)编辑 收藏

Navigate forth and back with ctrl+] and ctrl+t in Cscope

It is handy to be able to navigate the source code with Ctrl + ] in Cscope, but I always forget how to navigate back and waste effort many times. So for record, Ctrl+t can navigate back in Cscope.

One more time, Ctrl+] and Ctrl+t can navigate forth and back in Cscope.

posted @ 2010-03-29 14:20 InPractice 阅读(286) | 评论 (0)编辑 收藏

Learning Notes of TCP/IP Illustated Volume 2

How to read the source code in <<TCP/IP Illustrated Volume 2>>

1. Get the source code, original link provided in the book is not available now.
You may need to google it.

2. install cscope and vi.

3. refer to http://cscope.sourceforge.net/large_projects.html for the following steps.

It will include all the source code of the whole OS, not only the kernel.
find src -name '*.[ch]' > cscope.files

we actually only care kernel source.
find src/sys -name '*.[ch]' > cscope.files

4.  wc cscope.files
 1613  1613 45585 cscope.files

5. vim
:help cscope
then you can read the help details.

6. if you run vim in the folder where cscope.out resides. then it will be loaded
automaically.

7. Try a few commands.
:cs find g mbuf
:cs find f vm.h

They works. A good start.

P.S. this book is quite old, if you know it well and can recommend some better alternative for learning TCP/IP, please post a comments, Thanks in advance.


posted @ 2010-03-29 13:30 InPractice 阅读(132) | 评论 (0)编辑 收藏

童趣

我儿子在弹钢琴,他阿姨说,“哥哥就喜欢弹难的。”
我外甥女说:“哥哥要弹男的。妹妹要弹女的。”

posted @ 2010-03-26 14:41 InPractice 阅读(108) | 评论 (0)编辑 收藏

幼稚的关于寻找素数的猜测

在高中的时候,知道了用筛法可以得到素数。当时我还有一个错误的关于寻找素数的猜测。
以为用两个素数相乘,其附近存在素数的几率很高。比如, 7×11 = 77, 其附近有79,正好是素数。
当时已经发现11×11=121。7×17=119;但是错误的理解为只有其中一个是平方或次幂时才成立。
后来有了计算机,编程验证了一下,发现有很多的反例。对当初的错误猜测羞赧不已。


这个猜测虽然错的离谱,但是和现在的素数理论,尤其是孪生素数还是很有关系的。现在已经知道,
素数有无穷多个,但是素数在自然数中所占的比例逐渐趋近于零。

因此孪生素数在自然数中的比例也是趋近于零的。现在还没有证明孪生素数是否有无穷多个。

这个猜测的朴素之处在于,任何两个素数之乘积A,要么A是3n+2,要么A是3n+1;如果是3n+2,则只有A+2
才有可能是素数;如果是3n+1,则只有A-2才有可能是素数。但是,事实上,这个猜测成立的比例非常的低。

写了一个程序验证了一下。16位的整数中,大概只有 10% 能使假设成立。

posted @ 2010-03-26 14:37 InPractice 阅读(131) | 评论 (0)编辑 收藏

在Proxy环境中使用GIT需要解决的问题.

由于是在Proxy的网络环境,MSYSGIT 的 git clone 总是失败。需要配置如下环境变量。
export http_proxy="http://<proxy domain name>:<port>"
之后http协议git clone没有任何问题。但是用git 协议仍旧有问题。

之后发现git push 和 git pull 经常不能work。多次尝试后发现用更全的命令行参数可以解决问题。
过程如下。

git pull --fail
git pull origin --fail
git pull  git@github.com:ueddieu/mmix.git --it works.

It seems the Command line short cuts are lack of some user information, such as user name "git".
(which is kind of strange at the first glance.)

git push --fail
git push origin --fail
git push git@github.com:ueddieu/mmix.git master --it works.

Anyway, now I can check in code smoothly. :)

posted @ 2009-12-31 17:13 InPractice 阅读(822) | 评论 (1)编辑 收藏

Trouble caused by un-visible blank character

There are a few cases in which the un-visible blank character will cause
problem, but it is hard to detect since they are not visible.

One famous case is the '\t' character used by Make file, it is used to mark
the start of a command. If it is replace by blank space character, it does
not work, but you can not see the difference if you only look at the make file.
This kind of problem may get the newbies crazy.

Last week, I have encounter a similar issue, which is also caused by unnecessary
 blank space.
 
As you may know, '\' is used as line-continuation when you have a very long line, e.g.
when you configure the class path for Java in a property file, you may have something like this.

classpath=/lib/A.jar;/lib/B.jar;\
/lib/C.jar;/lib/D.jar;\
/lib/E.jar;/lib/log4j.jar;\
/lib/F.jar;/lib/httpclient.jar;

But if you add extra blank space after the '\', then you can not get the complete
content of classpath. Because only when '\' is followed by a '\n' on Unix or '\r''\n'
on Windows, it will work as line-continuation ; otherwise, e.g '\' is followed by
' ''\n', the line is complete after the '\n', the content after that will be the start of
a new line.

Fortunately, it is easy to check this kind of extra blank space by using vi in Unix.
use command '$' to go to the end of line, if there is no extra blank space after '\',
the current position should be '\', if there are any blank space after '\', the current position
is after the '\'.
 

posted @ 2009-07-01 11:48 InPractice 阅读(177) | 评论 (0)编辑 收藏

妈妈和儿子

妈妈和儿子
妈妈,你最近不吃鱼,变笨了吧――2009.6.2

儿子又要求录音了。我们按着台词在dialog。
“……”儿子
“……,I like mangoes”妈妈
“妈妈,我昨天刚教会你,又忘了?是I like watermelon。”
“哦,妈妈现在记性不好了!”
“是你这几天不吃鱼了吧,变笨了吧。明天多吃点!”

妈妈你穿这衣服蛮可爱――2009-6-9晚
儿子挑选的故事讲完了。“好,ok,我们睡觉吧!”我说。
“唉,妈妈,还没录音呢,我去拿mp3。”自从第一次提议给他录音,儿子每天都要求我能做到。
……
“……,妈妈,你蛮可爱的!……”录音正起劲,儿子突然插了一句题外话。
“什么?”我没听清。
“你穿这衣服蛮可爱的!”儿子贼贼的笑着又重复了一遍。“因为你的衣服象小斑马呀!”我终于明白。


posted @ 2009-06-10 14:26 InPractice 阅读(173) | 评论 (0)编辑 收藏

安装openldap遇到的一个小问题。

我安装openldap时主要是参考了http://hexstar.javaeye.com/blog/271912

我遇到的一个新问题是执行ldapsearch报错如下:
can not find libdb-4.7.so.
我的解决办法是,建立符号链接/usr/lib/libdb-4.7.so, 后者指向/usr/local/BerkeleyDB/lib/libdb-4.7.so
之后没有遇到其他问题。

posted @ 2009-05-29 10:33 InPractice 阅读(133) | 评论 (0)编辑 收藏

和儿子一起长大

凡事都有其内在原因,即使是表面上毫无道理的行为,也有其内在的原因。今天再次认识到这个

道理,还是因为今天早上和我儿子的一段插曲。

 

今天早上,我儿子不肯起床,在床上哭闹,不让他妈妈去上班,要他妈妈陪他睡觉。

他妈妈要赶班车,没时间陪她,留我在家里。我陪他睡了一会,聊了十分钟,才知道他是有原因

的。

 

昨天晚上,我和她妈妈都很累,我就说今天我们早点睡觉,和儿子一起睡好了。可是因为刚刚

回上海,有很多事情要做,最后还是忙到十点半才睡。儿子就说爸爸说谎了。当然他可能还有

其它的原因,比如想我们每天和他一起睡觉。

posted @ 2009-02-03 15:46 InPractice 阅读(98) | 评论 (0)编辑 收藏

The analysis of MOR(MXOR) instruction implementation in MMIXWare

The analysis of MOR(MXOR) instruction implementation in MMIXWare
 
 -- A stupid way to understand the source code.
 
 the implementation of MOR(MXOR) is in file: mmix-arith.w
 436 octa bool_mult(y,z,xor)
 437   octa y,z; /* the operands */
 438   bool xor; /* do we do xor instead of or? */
 439 {
 440   octa o,x;
 441   register tetra a,b,c;
 442   register int k;
 443   for (k=0,o=y,x=zero_octa;o.h||o.l;k++,o=shift_right(o,8,1))
 444     if (o.l&0xff) {
 445       a=((z.h>>k)&0x01010101)*0xff;
 446       b=((z.l>>k)&0x01010101)*0xff;
 447       c=(o.l&0xff)*0x01010101;
 448       if (xor) x.h^=a&c, x.l^=b&c;
 449       else x.h|=a&c, x.l|=b&c;
 450     }
 451   return x;
 452 }
 
 It takes me several hours to understand the details.
 
 If we treat each octabyte as a matrix, each row corresponds to a byte, then
 y MOR z = z (matrix_mulitiply) y
 
 For a=((z.h>>k)&0x01010101)*0xff;
 (z.h>>k)&0x01010101 will get the four last bit in (z.h>>k). depends on the bit in last row,
 ((z.h>>k)&0x01010101)*0xff will expand the bit (either 0 or 1) into the whole row.
 e.g.
             ff
 *     0x01010101   
 ---------------
 =           ff
           ff
         ff
       ff
 ----------------
 =    ffffffff      
(depending on the last bit in each row of z, the result could be #ff00ff00. #ff0000ff, etc.)

similarily, b=((z.l>>k)&0x01010101)*0xff; will expand the last bit in each byte into the
whole byte.

over all, after these two step, the z becomes the replication of it's last row, since k vary
from 0 to 7, it will loop on all the rows actually.


 For c=(o.l&0xff)*0x01010101, it will get the last byte in o.l and populate it to other three byte.
 since it will not only or/xor h but also l. it is not necessary populate it to o.h.
 
 one example,
 let (z.h>>k)&0x01010101 = 0x01000101, then a= 0xff00ffff;
 let (z.l>>k)&0x01010101 = 0x01010001, then b= 0xffff00ff;
 let (o.l&0xff)=0xuv, then c= 0xuvuvuvuv;
  then a&c=0xuv00uvuv;
         b&c=0xuvuv00uv;
       
 consider the elements [i,j] in result x.  in this round, what value was accumalated in by operation
 or(xor).
 it is the jth bit in last byte of o.l & ith bit in last column of z.(do not consider looping now.)
 in this round, the 64 combination of i and j, contirbute the value to the 64 bits in z.
 
 Noticed that o loop on y from last byte to first byte. There are 8 loop/rounds, in another round.
 say kth round.
 the elements[i,j] will accumuate the jth bit in last (k + 1)th row & the jth bit in last (k+1)th
 column.
 that means the jth column in y multiply the ith row in z. it conform to the definiton for
 z matrix_multiply y.
 
 
         
       
       
 

posted @ 2009-01-16 10:54 InPractice 阅读(272) | 评论 (0)编辑 收藏

九连环游戏和数学

游戏和数学有密切的联系。最近在玩九连环,感受更深。

之所以开始玩九连环,是因为在高德纳的书中提到了格雷码和九连环的关系。为了理解生成格雷码的算法,特意买了九连环来玩。毕竟书上的
描述没有实际玩起来那么容易理解。

通过这个游戏,我不仅会解九连环了,而且掌握的生成格雷码的一种算法。

posted @ 2009-01-13 19:59 InPractice 阅读(398) | 评论 (0)编辑 收藏