Monday, March 16, 2009
查看库中的函数(objdump)
$ objdump -T *.so
就能看到什么库文件中含有相应的函数了。
从“迷失的8”到生成函数:小数展开的秘密(转)
小学时经常在计算器上面按12345679这个神秘的8位数。这个数牛就牛在,它乘以9的结果正好等于111111111。你可以在计算器 上输好12345679,然后问MM“你的幸运数字是多少”;如果她说“7”,你就在计算器上按“乘以63”,计算器上将会显示出清一色的7字,看上去无 比壮观。
假如123456789×9=1111111111的话,我倒不会觉得奇怪。网上流行过一个火星帖子,写了一大堆诸如111111111 * 111111111 = 12345678987654321的式子来展示数学之美,以至于大家会认为123456789×9的结果也一定是一串很有规律的数字。因此,如果我不在 这里说一句123456789×9其实并不等于1111111111的话,估计很多人都发现不了问题。事实 上,123456789×9=1111111101,偏偏就差一个“1”。而怪就怪在,去掉被除数中的数字“8”,偏偏又有了 12345679×9=111111111,一个极其别扭的算式反而得到了完美的结果。不要让你的直觉被数学之美所蒙蔽,数学上有大量出人意料的、看上去 很不对称的结论。
为什么偏偏要少一个“8”呢?难道这真的是算术中的一个不可抹去的疤痕?我们急需要寻求一个解释,填补上算术中的这个不和谐的“漏洞”。一种解释 是,我们看到了123456789×9=1111111101并不美观,想要对其进行改造,进而得到(123456789+1)*9 = 1111111101+9 = 1111111110,于是(123456789+1)*9/10 = 12345679*9 = 111111111。用这种办法的确可以解释“迷失的8”,不过这个解释并不漂亮。为了寻求一个更好的解释,我们来看一看111111111和9的关系。
或许大家都知道,利用等比数列求和,我们可以把任一循环小数还原为分数。111...11和9之间有一个非常精妙的联系:1/9 = 0.111... 。换句话说,1000000000/9取整之后就应该等于111111111。而这个神秘的12345679,就应该是1000000000/81取整后 的结果了。1/81到底等于多少呢?拿精度稍微高一点的计算器一算,我们发现1/81 = 0.01234567901234... 。原来,12345679的秘密全在1/81里面,12345679*9=111111111其实相当于是拿1/81乘以9,取得了1/9的小数部分。
现在余留的问题就是,为什么1/81的前面几位是.012345679呢?仔细观察这个小数,你会发现整个小数的循环节就是012345679,偏偏就少一个“8”。这到底是为什么呢?
为了解释一种反常的数学现象,一个有趣的思路就是,“如果不是这样,你觉得又该是怎样呢?”理想中,这种有悖于数学之美的事情是不应该发生 的,1/81要是等于0.01234567890123456789...就好了,或者更牛B一点的,有没有可能等于 0.0123456789101112131415...?哦,这个好像太夸张了,后面这个小数明显是一个无限不循环小数,不可能和一个有理数相等。不过 呢,Σn/10^(n+1)倒是有可能的。想到这一点,我们最初的谜题迎刃而解!

1/81=Σn/10^(n+1)这一猜测似乎很合理,究竟对不对呢?这和81又有什么关系呢?只需要注意到1/81=(1/9)*(1 /9),联想前面我们讲过的东西,我们就得到了一个虽然不严密但是颇有启发性的推理。111*111=12321,是因为111*111相当于把111错 位写成三行后加起来;类似地,前面提到的极端情形111111111 * 111111111 = 12345678987654321也是如此。那么,如果10个1乘以10个1呢?如果无穷个“1”乘以无穷个“1”呢?当我们计算1/9的平方时,我们 实际上在做的正是用无穷多个1去乘以无穷多个1,而乘式的第n+1列里恰有n个“1”,它们加起来并产生适当的进位后就得到了 0.0123456790123... 。
循环小数与整数之间存在着很多微妙的关系。很多时候,利用小数展开我们能解决很多无从下手的算术题目。小学奥数中有一道题目我印象极深:一 个位数小于30的、以“15”打头的整数,把这个“15”移到数的末尾后,新数正好是原数的5倍。问原数是多少。很少有人能想到,解开这道题的钥匙竟然是 分数和小数。假设有某个小数x的循环节就等于我们要求的数,那么
可知100x-5x=15,解得x=15/95=3/19。把3/19还原成小数,发现它的循环节是157894736842105263,问题就如此简单的解决了。
且慢,我还准备了更加精彩的数学魔术!让我们来看一看下面这套把戏:
100/9899 = 0.0101020305081321345590463 ...
牛B吧!两位两位的看,前面几个数正好形成Fibonacci数列!不过,再往后走,位数的限制迫使进位产生,打乱了原有的秩序。能让每个数的位数更长一些吗?能!请看:
1000/998999 = 0.001001002003005008013021034055089144233377610...
10000/99989999 = 0.000100010002000300050008001300210034005500890144...
100000/9999899999 = 0.00001000010000200003000050000800013000210003400055000890014400233...
......................
这个就更加奇怪了。为什么一个简简单单的分数展开之后竟然出现了Fibonacci数列?其实,道理和前面所讲的很相似。100/9899 显然是由100/(10000-100-1)得到的,让我们来看一下0.0101020305081321...乘以(10000-100-1)是否能还 原成100:
可以看到,这个“Fibonacci小数”的10000倍,减去它的100倍,再减去它自身,得到的结果正好是100,究其原因则是Fibonacci数列的递归性质。熟悉生成函数的读者猛地一拍大腿,唉呀!这不就是生成函数么!我在讲解生成函数的日志里曾经写道:
接下来我们要演示如何使用生成函数求出Fibonacci数列的通项公式。
Fibonacci数列是这样一个递推数列:f(n)=f(n-1)+f(n-2)。现在我们需要求出它的生成函数g(x)。g(x)应该是一个这样的函数:
g(x)=x+x^2+2x^3+3x^4+5x^5+8x^6+13x^7+...
等式两边同时乘以x,我们得到:
x*g(x)=x^2+x^3+2x^4+3x^5+5x^6+8x^7+...
就像我们前面说过的一样,这相当于等式右边的所有系数向右移动了一位。
现在我们把前面的式子和后面的式子相加,我们得到:
g(x)+x*g(x)=x+2x^2+3x^3+5x^4+8x^5+...
把这最后一个式子和第一个式子好好对比一下。如果第一个式子的系数往左边移动一位,然后把多余的“1”去掉,就变成了最后一个式子了。由于递推函 数的性质,我们神奇地得到了:g(x)+x*g(x)=g(x)/x-1。也就是说,g(x)*x^2+g(x)*x-g(x)=-x。把左边的g(x) 提出来,我们有:g(x)(x^2+x-1)=-x。于是,我们得到了g(x)=x/(1-x-x^2)。
原来,100/9899说穿了就是把x=1/100代入生成函数g(x)。
这下子就热闹了。考虑数列1, 4, 9, 16, 25, 36, ...的生成函数g(x)=x(1+x)/(1-x)^3,代入x=1/100得到g(1/100)=10100/970299,于是出现了:
10100/970299 = 0.0104091625364964 ...
当然,想要更牛B的也不难:
g(1/1000) = 1001000/997002999 = 0.001004009016025036049064081100121144169 ...
再来看看数列2, 4, 8, 16, 32, ...的生成函数g(x)=2x/(1-2x),利用它可以产生出
g(1/100) = 1/49 = 0.0204081632 ...
或许有人会恍然大悟,原来,1/7=0.142857...也不是一个巧合。14是7的两倍,28是7的四倍,57是7的八倍加一,这都是因为它们是7乘以“2的幂序列”并产生适当进位后得到的。
重新回到我们先前讨论的话题,我们惊奇地发现,数列0, 1, 2, 3, 4, ...的生成函数为g(x)=x^2/(1-x)^2。于是:
g(1/10) = 1/81 = 0.0123456790123...
Friday, March 13, 2009
Windows 下播放视频文件花屏现象的解决
桌面上右击属性 然后点设置 然后点高级 然后点疑难解答 然后拖上面的滑条,拖到无就肯定可以放了(来源:http://bbs.feey.cn/thread-4563-1-1.html)
原来是显卡加速的原因,我把滑块置于第三档就正常,在第四档就花了。也就是说,只要调节到“禁用所有的 DirectDraw 和 Direct3D 加速程序”就能正常播放那些视频了。
Thursday, March 12, 2009
查了下 assert.h 的用法
考上机关公勤后,这几天在公司没事,就有空研究起 Linux 下的 C 语言来。之前学得很空泛,不了解所以然,连 gcc 的 -I、-L、-l 都分不清楚,连 makefile 也不会写。于是下载了 GNU 的 coreutils 源代码进行研究。当我看 factor.c 的时候看到了一个奇怪的头文件:
#include <assert.h>
于是就 google 开了,发现 assert() 真是个好东西,可以在调试过程中帮上很大的忙。下面转贴一篇网文(来源:<http://www.cnblogs.com/phonefans/archive/2008/12/24/1361381.html>):
=========================
assert() 函数用法
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:
#include <assert.h>
void assert( int expression );
assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,
然后通过调用 abort 来终止程序运行。
请看下面的程序清单badptr.c:
1 #include <stdio.h>
2 #include <assert.h>
3 #include <stdlib.h>
4 int main( void )
5 {
6 FILE *fp;
7
8 fp = fopen( "test.txt", "w" );//以可写的方式打开一个文件,如果不存在就创建一个同名文件
9 assert( fp ); //所以这里不会出错
10 fclose( fp );
11
12 fp = fopen( "noexitfile.txt", "r" );//以只读的方式打开一个文件,如果不存在就打开文件失败
13 assert( fp ); //所以这里出错
14 fclose( fp ); //程序永远都执行不到这里来
15 return 0;
16 }
已放弃
使用assert的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。
在调试结束后,可以通过在包含#include <assert.h>的语句之前插入 #define NDEBUG 来禁用assert调用,示例代码如下:
#include <stdio.h>
#define NDEBUG
#include <assert.h>
用法总结与注意事项:
1)在函数开始处检验传入参数的合法性
如:
1 int resetBufferSize(int nNewSize)
2 {
3 //功能:改变缓冲区大小,
4 //参数:nNewSize 缓冲区新长度
5 //返回值:缓冲区当前长度
6 //说明:保持原信息内容不变 nNewSize<=0表示清除缓冲区
7 assert(nNewSize >= 0);
8 assert(nNewSize <= MAX_BUFFER_SIZE);
9
10 }
2)每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败
不好: assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);
好: assert(nOffset >= 0);
assert(nOffset+nSize <= m_nInfomationSize);
3)不能使用改变环境的语句,因为assert只在DEBUG个生效,如果这么做,会使用程序在真正运行时遇到问题
错误: assert(i++ < 100)
这是因为如果出错,比如在执行之前i=100,那么这条语句就不会执行,那么i++这条命令就没有执行。
正确: assert(i < 100)
i++;
4)assert和后面的语句应空一行,以形成逻辑和视觉上的一致感
5)有的地方,assert不能代替条件过滤
==================
呵呵,真棒!
Saturday, January 03, 2009
硬盘分区
对管理任何一种操作系统来说,为求得系统的平稳运行,硬盘分区都是必需的。对人来说,分区又意味着什么呢?合理的分区意味着速度,效率,质量。当然这仅仅只是从一个角度来说的。要平衡计算机的效率和人对文件的组织管理来分区是需要点艺术的,很难,但也不难。
《LPI 权威指南》(下面简称 LPI)中建议,分区要按计算机的实际需要作文章。Web 服务器、文件服务器和个人机分法均有所不同。LPI 给了一个针对 80 GB 硬盘一般性的建议:
Partition Type Mounted filesystem Size
/dev/hda1 Primary /boot 100 MB
/dev/hda2 Primary / 500 MB
/dev/hda3 Extended - -
/dev/hda5 Logical /usr 4 GB
/dev/hda6 Logical /var 2 GB
/dev/hda7 Logical /opt 1 GB
/dev/hda8 Logical /tmp 500 MB
/dev/hda4 Primary (swap partition) 1 GB
/dev/hdb1 Primary /home 60 GB
按照 LPI 所给的建议,我对 80 GB 和 120 GB 的硬盘作了下相应的划分:
----- 80 GB -----
Partition Type Mounted filesystem Size
/dev/sda1 Primary /boot 512 MB
/dev/sda2 Primary /usr 15 GB
/dev/sda3 Primary / 4 GB
/dev/sda4 Extended - -
/dev/sda5 Logical /var 2 GB
/dev/sda6 Logical (swap partition) 2 GB
/dev/sda7 Logical /tmp 512 MB
/dev/sda8 Logical /home others
----- 120 GB -----
Partition Type Mounted filesystem Size
/dev/sda1 Primary /boot 512 MB
/dev/sda2 Primary /usr 15 GB
/dev/sda3 Primary / 5 GB
/dev/sda4 Extended - -
/dev/sda5 Logical /var 2 GB
/dev/sda6 Logical (swap partition) 2 GB
/dev/sda7 Logical /tmp 1 GB
/dev/sda8 Logical /home others
以上仅仅是我对自己系统的一种划分,不能适应所有的情况。
Sunday, September 07, 2008
VIM 语法高亮设置
if &t_Co > 1
syntax enable
endif
就可以设置让支持彩色的终端显示彩色。
vim 根据底色来选择前景色:如果底色是深色的,那么前景色为浅色的;如果底色是浅色的,那么前景色为深色的。设置方法:
: set background=dark
: set background=light
Monday, July 28, 2008
Thursday, July 03, 2008
惊魂交换机
接下来的几分钟内相安无事,网络正常...
突然,网络中断了,而且发现与弱电房同一楼层的所有电脑都死机。但是把网线拔掉电脑又正常。我一下子就慌了,很快意识到这可能跟我的操作失误有关。周围围过来的人越来越多,都在埋怨为什么上不了网。
我重新把那台电脑移了过来,再次连接交换机,然后试了下硬 reset。故障依旧。“坏了,可能把交换机弄坏了!”我心想。于是我和我的同事一起考虑问题出在哪里,反正网络不通,那就死马当活马医吧!
判断一:电压不稳
这个判断刚说就被否定了,因为其他不在这个网络上的计算机上网完全正常。而且在本网段上的电脑拔掉网线就正常,连上就死机。
判断二:查看光纤适配器,看是否是网络攻击造成的
操作:将网线直接接到光纤适配器的内部端口,设置计算机上的 IP 地址同外网的 IP 同一网段。然后 ping 外网 ip
现象:有数据回应
结论:光线适配器没问题,而且也没有网络攻击
判断三:路由器有问题
操作:恢复光纤适配器和路由器的连接,将网线直接接到路由器的内部端口
现象:网络无连接。但是当用网线连接交换机时灯是点亮的
结论:路由器内部端口可能有问题,但也可能没有问题
判断四:交换机坏了
操作:恢复路由器和交换机的连接,将网线连接到交换机上
现象:过大约 5 秒时间电脑死机
结论:交换机内部可能真的出了问题
判断五:网络可能出现阻塞,先配置下交换机
操作:将光纤适配器和路由器的连接、路由器和交换机的连接断开,用 console 连接交换机。超级终端登录。重置交换机。然后再将交换机与路由器相连。
现象:还是过大约 5 秒时间电脑死机
结论:“糟了!要赔万把块 RMB 了!”
判断六:路由器配置有问题
操作:将交换机与路由器的连接断开,用 console 连接路由器。超级终端登录。重启路由器进入 monitor# 模式,然后查看配置文档。
现象:没有异常,配置文档与原先一致
结论:路由器配置无误。(“噩梦啊!”)
判断七:路由器与交换机配合时出错
操作:还是用 console 连接路由器。连接好交换机和路由器。用超级终端登录。
现象:出现异常!终端不断显示“Another host is using mac address **:**:**:**:**:**”
结论:显然有设备和路由器的 MAC 地址冲突了!
判断八:交换机的 MAC 地址和路由器的 MAC 地址冲突
操作:重刷交换机的 firmware?不现实。(“怎么办?怎么办?!!!”)
判断九:子网中的电脑 MAC 地址和路由器的 MAC 地址冲突,有可能因为 MAC 地址欺骗
操作:将所有连接交换机的线拔下,然后一个一个插回去。判断当有哪个线路造成了计算机死机,那么可以顺藤摸瓜查到问题电脑。
现象:所有的线都插回去了,都没发现异常。而且这次计算机没有死机
结论:还用说吗?我不必赔交换机啦!
唉,这个问题真是复杂,当到网上查找这个“Another host is using mac address **:**:**:**:**:**”字串,居然没查到一例一样的问题!于是把这个问题整理一下,发到博客上来。:-)
Tuesday, July 01, 2008
D-Link DI2621 路由器密码重置
1. 将数据线连接至 console 口;
2. 打开超级终端程序,连接上路由器;
3. 重启路由器;
4. 当终端显示第一串消息的时候快速输入 :config-aaa;
5. 终端将进入 monitor# 模式。
可惜里面说的方法并不适合该款路由器。我试了十几遍都不行,路由器完全没有给我足够的时间来输入这串命令!无奈,只好先上官方网站上下了份 DI2621 的说明 doc.doc。在里面提到了一个方法可以进入到 monitor# 模式:
1. 将数据线连接至 console 口;
2. 打开超级终端程序,连接上路由器;
3. 重启路由器;
4. 当终端显示第一串消息的时候按 “Ctrl + Break”键;
5. 进入 monitor# 模式。
按照这个办法还真的可以,顺利进入了管理界面。重命名 startup-config 文件之后再重启路由器。OK!可以通过 admin 用户名和空密码进入配置路由器了!
Sunday, June 22, 2008
Blogger 又开通啦!
不过今后不会再出现这种情况了,被封的日子里可以使用 gladder 插件!呵呵。


