More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  剪燈閒筆ProfileFriendsBlogMore Tools Explore the Spaces community

剪燈閒筆

我的精神家園
View space
酷睿科技

感谢您的光临!
  • 7/8/2008 1:06:55 PM
    博主的文章很好,可以做个友情链接吗?
    我的文章大多是我自己写的,刚换了WP程序,还有很多文章没转移过来,但现在已经有足够的文章,
    zunch’s Blog
    http://www.zunch.org

中文 MSDN 的一处翻译错误

【摘要】本文叙述了中文 MSDN 的一处翻译错误,并给出正确的译文。
【分类】英语 » 中文翻译 | 计算机 » 程序设计 » 环境和工具
【标签】翻译错误 | Visual C++ 自定义关键字
2008-7-30
在进行 C/C++ 编程时,我们常用 typedef 自定义类型来提高代码的可读性。有时我们希望 IDE 中这个自定义的类型也能象普通关键字一样高亮显示。Visual C++ 提供了一种方法实现这个功能,参见 MSDN 文章:在 Visual C++ 中定义关键字
这篇文字大概是在机器翻译的基础上经过人工审核整理而成的,纰漏颇多,特别是其中的第三条:
在同一目录下将 usertype.dat 以一个纯文本文件格式另存为 devenv.exe。
这句话着实不知所云,勉强理解的话大概是说:
在当前目录下复制 usertype.dat,并把新文件重命名为 devenv.exe。
好在我们能够很方便地找到它的英文原文 Defining Keywords in Visual C++,同样是第三条:
Save usertype.dat in the same directory as devenv.exe, as a text-only file.
译成中文就是:
以纯文本文件格式把 usertype.dat 保存在 devenv.exe 所在的目录。
这才是原文要表达的意思。

Diablo II 装备的一致性问题

【摘要】本文叙述了 Diablo II 中存在的一个与装备次序有关的一致性问题,并提出解决的办法。
【分类】计算机 » 程序设计 » 逻辑和规范 | 电子游戏 » Diablo
【标签】Diablo II 装备 | 一致性问题
2008-7-31
Diablo II 中不少物品需要一定属性才能装备,比如下面这条暗金腰带就需要 60 的力量:
Many items in Diablo II require specific attributes for equipping. E.g., the unique belt below needs 60 strength:
一般情况下,如果力量不足 60,角色是无法装备这条腰带的。但是这条腰带自身有力量 +5 的属性,论理只要力量达到 55,就应当能装备它。可惜实际上不行。
Generally if the character's strength didn't meet 60, the belt would be not available for him/her. One the other hand, the belt had an attribute +5 strength. It meant that as long as the character got 55 strength, theoretically he/she should wear the belt without any problem. But actually it was clearly not the truth.
有没有办法做到这一点呢?有的。我们找一条同样力量 +5 的护身符,放在物品栏中。这样这条腰带就可以被成功装备了:
Any idea for that? Let's find a charm with +5 strength as well, and placed it in the inventory. In such a way the belt was equipped succesfully.
现在角色的力量达到了 65,对于这条腰带来说,护身符已经多余了。我们把护身符撤掉,可以看到腰带仍然完好地挂在腰上:
So far the character's strength had met 65. The charm was unnecessary any more regarding the belt. So we removed it. Finally you would see that the belt was still around the waist availably.
这就是 Diablo II 装备的一致性问题:同样的物品,因为装备次序不同,结果也不同。
This is just the consistency problem of Diablo II: different equipping order may lead to different result even if the items are same.
要解决这个问题,考虑下面的办法之一:
  • 装备物品前先加上物品自身的属性,而后判断它是否能够装备;
  • 允许装备未达到属性等级要求的物品,如果装备后的属性仍不能满足条件,令其状态不可用;(推荐)
  • 对于有属性等级要求的物品,其魔法属性中不要再包含这一属性。
To solve the problem, we may consider either:
  • Add the attributes of the item before equipping. Then check if the final attributes meet the requirement, or
  • Allow to equip the item whatever it meets the requirement. If it doesn't meet the requirement yet after equipping, make its state not available, or (recommendation)
  • For the item that has attribute restrictions, do not include these attributes again to its inherent attribute list.
Diablo III 会不会还有这个问题,我们拭目以待。
If Diablo III still has such problem? we wait expectantly.

手动下载 .NET Framework 源代码

【摘要】本文阐述了 .NET Mass Downloader 下载 .NET Framework 源代码的原理。
【分类】计算机 » 程序设计 » 环境和工具 | 计算机 » 程序设计 » .NET
【标签】.NET Framework 源代码 | 微软符号服务器 | Pdb 文件
2008-7-25
数月前,微软开放了部分 .NET Framework 源代码,Visual Studio 2008 和 Visual Studio 2005 用户可以通过配置符号服务器(Symbol Server)获取这部分代码。不过,不象设计 MFC 程序那样编辑时就能进入源代码,Visual Studio 只允许 .NET 程序员调试程序的时候打开当前代码相关的 .cs 文件。这些 .cs 文件没有缓存到本地硬盘,缓存到本地硬盘的是 .pdb 文件,也就是 Visual Studio 程序数据库(Program DataBase)。我们知道,.pdb 是保存程序调试信息的文件,并不包含程序源代码,这对于希望系统阅读 .NET Framework 源代码的用户来说十分不便,于是一款称为 .NET Mass Downloader 的程序应运而生。
顾名思意,.NET Mass Downloader 就是批量下载 .NET Framework 源代码的下载器。它不但能下载 .pdb 文件,还能下载每个 .pdb 文件对应的一系列 .cs 文件。这种做法可能不符合微软的商业利益,但注意到这个软件是发布在微软的开源社区 CodePlex 上的,我猜想它的存在是得到微软许可的。
.NET Mass Downloader 发布有一段时间了,我是昨天才知道它的,也很偶然地下载了它的源代码。因为重装 Visual Studio 2008 发生错误——我安装了 Silverlight 2 Tools Beta 2,接着安装 Visual Studio 2008 SP1 Beta。结果后者安装失败,提示要先卸载 KB944899 这个补丁。这个补丁恰好与 .NET Framework 源代码有关。可是我没有安装 KB944899,猜想可能是 Silverlight 2 Tools Beta 2 安装了其它的补丁涵盖了 KB944899。确实是这样,问题出在 KB949325 上,卸载 KB949325 后一切正常——我顺手打开新下载的 .NET Mass Downloader 源代码测试 Visual Studio 2008 的安装是否成功。
下面的教程就是这次粗略浏览 .NET Mass Downloader 源代码的结果。当然,有了 .NET Mass Downloader 这样好的工具,没有谁会真的去手动下载 .NET Framework 源代码。这篇教程的目的是从侧面窥视微软符号服务器(Microsoft Symbol Servers)的工作原理。
  1. 安装 .NET Framework 3.5
    这一步很重要却往往被忽略。因为目前微软只提供 .NET Framework 3.5 程序集(assembly)的部分源代码,安装其它版本的 .NET Framework,你可能下载不到任何代码,因为同名程序集在不同版本的 .NET Framework 下可能不同。举个例子,所有版本的 .NET Framework 都有 System.dll 这个程序集,它在各版 .NET Framework 下的版本号如表所示:
    .NET Framework 版本 System.dll 版本 编译日期 文件大小
    1.0 1.0.3705.0 2002-1-5 1,136KB
    1.1 1.1.4322.573 2003-2-21 1,188KB
    2.0, 3.0 2.0.50727.42 2005-9-23 2,948KB
    2.0 SP1, 3.0 SP1, 3.5 2.0.50727.1433 2007-10-24 3,004KB
    3.5 SP1 Beta 2.0.50727.3031 2008-4-18 2,964KB
    显然,如果文件的版本不一样,它的源代码也不一样。这就是安装 .NET Framework 3.5 的原因。对于这个问题,我想再严谨些。下载 .NET Framework 源代码,其实并不一定非要安装 .NET Framework,安装 .NET Framework 只是简便的做法。读完下面的步骤我们可以知道,这里真正需要的是要下载的源代码对应的那个程序集文件,类似于上面例子中的 System.dll。你有许多办法获得这个文件,比如下载 .NET Framework 3.5 安装包,手动从中提取文件。
  2. 为浏览器添加新的 User-Agent:Microsoft-Symbol-Server/6.8.0004.0。
    • 如果你的浏览器是 Internet Explorer 7,你可以在注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\
      CurrentVersion\Internet Settings\5.0\User Agent\Post Platform 位置新建字符串(REG_SZ),值为 Microsoft-Symbol-Server/6.8.0004.0,数据留空。
    • 如果你的浏览器是 FireFox 3,你可以在 about:config 页面中新建字符串 general.useragent.override,设置它的值为 Microsoft-Symbol-Server/6.8.0004.0。
    • 如果你使用其它浏览器,如 Maxthon,或者安装了浏览器增强插件,如 IE7Pro,你可以尝试在它们的配置中设置 User-Agent 的值。
    这一步是为了让符号服务器能够识别其后的下载请求。设置完成后需要重启浏览器。
  3. 在程序集文件中检索 PDB 信息
    以 mscorlib.dll 2.0.50727.1433 为例,它一般位于 C:\Windows\Microsoft.NET\Framework\v2.0.50727 目录下。
    • 如果你安装了 Visual C++,你可以用它的命令行工具 dumpbin 导出整个 mscorlib.dll 的 PE 结构信息。找到 Debug Directories 一段,注意 Format 后面的值:RSDS, {56470DDE-A10F-45F4-A409-7FF9274F4923}, 1, mscorlib.pdb。
      这是 CV_INFO_PDB70 结构的数据,含义如下:
      类型 名称 含义
      DWORD CvSignature RSDS 表明当前 CodeView 块的格式是 PDB 7.0
      GUID Signature {56470DDE-A10F-45F4-A409-7FF9274F4923} .pdb 文件的数字签名
      DWORD Age 1 .pdb 文件的增量更新标识
      BYTE[] PdbFileName mscorlib.pdb 以 \x0 结尾的 .pdb 文件的文件名
    • 如果你熟悉 PE/COFF 的结构,可以用普通的十六进制编辑器查找字符串“RSDS”,或者依 PE 结构顺次找到下面的数据:
    这些数据用于在符号服务器上定位 .pdb 文件。
  4. 下载 http://referencesource.microsoft.com/symbols/mscorlib.pdb/56470DDEA10F45F4A4097FF927
    4F49231/mscorlib.pd_
    不难看出这个地址是如何来的:
    • 首先是微软符号服务器地址 http://referencesource.microsoft.com/symbols;
    • 其次是 .pdb 文件的文件名 mscorlib.pdb;
    • 再次是它的 GUID 56470DDEA10F45F4A4097FF9274F4923;
    • 而后是增量更新标识 1;
    • 最后还是 .pdb 的文件名,不同的是,这里的扩展名为 .pd_。
    顺便提一下,直接用 Internet Explorer 下载这个文件常常会半途中断,而且 IE7Pro 的 MiniDM 不支持 User-Agent 设置。因此这里 FireFox 是更好的选择,用它直接下载或者通过 FlashGot 插件下载均可。如果是直接下载,和 Internet Explorer 一样,下载的内容会以网页形式呈现。这时不能直接保存页面,而应该打开页面的源代码,在那里保存文件为 mscorlib.pd_。
  5. 解压下载的 mscorlib.pd_
    mscorlib.pd_ 是 cab 格式的文件,常见的压缩工具都支持这种格式。也可以用 Windows 自带的命令行工具 expand 解压。解压后得到 mscorlib.pdb。
  6. 在 mscorlib.pdb 中找出源代码文件的下载地址
    用文本编辑器打开 mscorlib.pdb,在乱码后面找到字符串 SRCSRV: ini --------------------------------------------。从这里开始的文本记录了 mscorlib.dll 源代码文件的文件名和其它必要信息。注意下面几个重要的名称/值对:
    • 形如 HTTP_ALIAS=Http://ReferenceSource.microsoft.com/source/.net/8.0 的根地址;
    • 形如 HTTP_EXTRACT_TARGET=%HTTP_ALIAS%/%var2%/%var3%/%var4%/%fnfile%(%var1%) 或者,
    • 形如 SD_EXTRACT_TARGET=%targ%\%var2%\%fnbksl%(%var3%)\%var4%\%fnfile%(%var1%) 的逻辑地址。
    逻辑地址要转换成真实地址,还必须有上面各变量 %x% 的实际值,这些值就在形如 f:\RedBits\ndp\clr\src\BCL\System\
    Object.cs*DEVDIV*depot/DevDiv/releases/whidbey/REDBITS/ndp/clr/src/BCL/System/Object.cs*1 的字符串中。
    就以这个字符串为例,它对应的逻辑地址是 %targ%\%var2%\%fnbksl%(%var3%)\%var4%\%fnfile%(%var1%)。
    • 用固定地址 Http://ReferenceSource.microsoft.com/source/.net/8.0 替换 %targ%。如果逻辑地址包含的变量是 %HTTP_ALIAS% 而不是 %targ%,则用相应的 HTTP_ALIAS 值替换;
    • 把上面的字符串以星号为分隔符分成四节:
      • 用第一节中的文件名 Object.cs 替换 %fnfile%(%var1%);
      • 用第二节 DEVDIV 替换 %var2%;
      • 用第三节 depot/DevDiv/releases/whidbey/REDBITS/ndp/clr/src/BCL/System/Object.cs 替换 %var3%;
      • 用第四节 1 替换 %var4%;
    • 把 %fnbksl% 括号中值的斜杠号替换成反斜杠号。
  7. 下载 Object.cs 源代码
    用浏览器打开上面的地址,微软符号服务器并没有直接返回要下载的文件,而是返回一份 EULA(最终用户许可协议)。找到协议中形如 Accept=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 的字符串。把这串字符作为之前地址的参数,添加到它的后面。这就得到了最终的地址:http://referencesource.microsoft.com/source/.net/8.0/devdiv/depot/devdiv/releases/whidbey/
    redbits/ndp/clr/src/bcl/system/object.cs/1/object.cs?accept=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    ,这就是我们要下载的 Object.cs 源代码的地址。
就在我写这篇教程的时候,Microsoft Symbol Servers 正巧在调整,时时连接不上,并且下载到的 .pd_ 文件版本也不一样。如果你也遇到这种情况,请隔天再试。

未见诸文档的 Windows 错误

【摘要】本文列举了 Windows 下几个迄今尚未修复的错误。
【分类】计算机 » 软件 » Windows
【标签】Windows bug | 回收站界面更新 | 文件名非法字符 | 剪贴板
2008-6-20
  • 回收站界面更新问题
    问题描述
    在回收站窗口中“清空回收站”,有时会发现清空后文件仍然留在窗口里。其实文件确实是删掉了,只是界面没有更新。来看下面的截图:
    如图所示,桌面上的回收站图标是空的,窗口中“清空回收站”的按钮是无效的,说明回收站已经清空。可是回收站窗口内却仍有若干文件。
    重现步骤
    此错误遇到过几次,但无法重现。
    适用平台
    Windows Vista、Windows Server 2008 所有版本和补丁包。
  • 文件名非法字符问题
    问题描述
    当我们用剪贴板中含有文件名非法字符(/ \ : * ? " < > |)的字符串重命名文件或文件夹时,系统会自动过滤这些字符,并将过滤的结果复制回剪贴板。
    重现步骤
    1. 复制地址 http://localhost 到剪贴板;
    2. 重命名任一文件,把上面的地址粘贴到重命名的编辑框中,系统提示文件名不能包含冒号和斜杠号,确定或取消重命名;
    3. 打开记事本,把剪贴板的内容粘贴到记事本中,这时记事本显示 httplocalhost
    错误分析
    记事本显示的结果显然是错误的。我们知道,剪贴板是系统共享信息的临时区域。当“剪切”或者“复制”行为发生的时候,数据被移入剪贴板,剪贴板内容改变;当“粘贴”行为发生的时候,数据被移出剪贴板,但剪贴板内容保持不变。因此上面记事本显示的结果应当是最初的地址 http://localhost,而不该是过滤后的字符串。为了更多地了解这里的错误,我们再次重复上面的实验,不过这回把地址 http://localhost 换成 300 个 a 组成的字符串。因为文件名长度有一定限制,不能达到 300,超出的部分只能被舍去。我们就要看看这时候的剪贴板是不是也象上面一样剩下残缺的字符串。事实并非如此,300 个 a 被完好地存留下来,未被截短。据此可以大致猜测,错误发生的位置当在 Windows Explorer 过滤非法字符附近。
    适用平台
    Windows XP、Windows Server 2003、Windows Vista、Windows Server 2008 所有版本和补丁包。

【注】上面列举的适用平台,我并没有完整地测试过,部分结论来自记忆和推断,但我想大概不会出现例外。

双鱼 香草 咖啡(一)

【分类】计算机 » 编程语言 » Java
【标签】JDK | 线程安全
下面是 java.awt.Component 的代码片段,用于获取当前组件的背景色。
public Color getBackground() {
Color background = this.background;
if (background != null) {
return background;
}
// ...
}
初次读到这里时,想不明白 Color background = this.background; 这条语句的用意,第一个反应这是 JDK 经过多次版本变迁后不经意留下的代码碎片。这理由很快就被否定,原因是 Component 类中有大量类似的语句,很难想象 JDK 程序员会对如此频繁出现的冗余代码熟视无睹。既然这样,那这条语句必定有它的作用,我又想到四条理由:一是为了遵循与相似代码一致的代码风格;二是为了边际代码的安全,防止日后由于疏忽或误解而对代码做出错误的改动;三是为了将来需要扩展时,不必更改过多的代码;四是为了提高代码的执行效率,进行编译器顾及不到的优化。这四条理由都可能导致非常规代码的产生,但这里显然又都不是。
想了一小会,几乎要放弃的时候,我突然意识到这可能和线程安全有关。这么一想,思路豁然开朗。用局部变量 background 代替域变量 background 可以防止程序执行了 background != null 的判别后可以进入但还没有进入 return background; 时被别的线程修改了域变量 background 的值。否则,这两处的 background 可能不同值,那么 background != null 的保护性判别就失去了意义。
问题似乎该结束了,但有一个问题,如果上面的情形真的发生,即当前线程准备执行 return background; 时被另一线程修改了域变量 background 的值,则当前线程的 getBackground() 返回的值并不能反映最新的 background 的变化,所以这里的线程安全有瑕疵。要解决这个问题,简单的办法是用 synchronized 对这块临界区加锁,Component 类中就有大量这样的例子。但是同时,我们知道,synchronized 是很影响性能的,getBackground() 由于只涉及到对域变量 background 的读操作,所以没有必要加锁。也说是说,getBackground() 的实现也只能象上面那样——因为没有简单的办法做到更完美。
但我还是找到一个办法让问题变得简单,这需要扩展 Java 语法。如果我们有两个同步关键字:读同步 readsync 和写同步 writesync。当两个线程都进入 readsync 临界区时,互不加锁;当一个线程位于 readsync 临界区,另一个线程企图进入 writesync 临界区,或者反过来,一个线程位于 writesync 临界区,另一个线程企图进入 readsync 临界区,或者两个线程都企图进入 writesync 临界区时,实现同步。这既可以解决上面的线程安全问题,又不损失性能。更精细地,readsyncwritesync 不仅像 synchronized 那样能同步类和对象,还能同步类的域变量,比如上例,即用 readsync(background) 来同步域变量 background。
如果不扩展 Java 语法,也可以通过改进编译器来实现上述设想。仍用 synchronized 来标识,编译器自动分析临界区内哪些域变量是读同步,哪些是写同步,这不困难。困难的是,编译器无法知道临界区内哪些域变量是无须同步的。

焦晃《蜀道难》正音

【分类】汉语 » 普通话 | 文学 » 诗词
【标签】焦晃 | 朗诵 | 蜀道难
焦晃的朗诵颇见功力。他的嗓音浑厚而低沉,感情粗犷而沧桑,尤其这篇《蜀道难》的表现,尽可与专业播音员比肩。遗憾的是,不知出于何种原因,焦晃这篇吟咏里的字音误读俯拾皆是,听来如芒在背,如鲠在喉,真是遗珠之恨。这里以列表的形式列出这些错误,希望初学者在欣赏优秀作品的同时,免受它的误导。
原文 读音辨误
蜀道难  
噫吁嚱,危乎高哉! 噫吁嚱:此三字读音争议较大,但读作 yī hū xī 的恐怕绝无仅有。
哉:zài(误);zāi(正)。
蜀道之难难于上青天!  
蚕丛及鱼凫,开国何茫然!  
尔来四万八千岁,不与秦塞通人烟。 尔:ér(误);ěr(正)。
与:yù(误);yǔ(正)。
西当太白有鸟道,可以横绝峨嵋巅。  
地崩山摧壮士死,然后天梯石栈相钩连。  
上有六龙回日之高标,下有冲波逆折之回川。  
黄鹤之飞尚不得过,猿猱欲度愁攀援。  
青泥何盘盘!百步九折萦岩峦。  
扪参历井仰胁息,以手抚膺坐长叹。 胁:xiè(误);xié(正)。
息:xì(误);xī(正)。
抚:fú(误);fǔ(正)。
问君西游何时还?畏途巉岩不可攀。 畏:wēi(误);wèi(正)。
但见悲鸟号古木,雄飞雌从绕林间。 号:hào(误);háo(正)。
雌:cī(误);cí(正)。
又闻子规啼夜月,愁空山。 闻:wēn(误);wén(正)。
蜀道之难难于上青天,使人听此凋朱颜。  
连峰去天不盈尺,枯松倒挂倚绝壁。 倚:yī(误);yǐ(正)。
飞湍瀑流争喧豗,砯崖转石万壑雷。 湍:tuán(误);tuān(正)。
砯:pēng(误);pīng(正)。
转:zhuàn(误);zhuǎn(正)。
其险也如此,嗟尔远道之人胡为乎来哉?  
剑阁峥嵘而崔嵬,一夫当关,万夫莫开。 嵘:rōng(误);róng(正)。
嵬:wēi(误);wéi(正)。
夫:fù(误);fū(正)。
所守或匪亲,化为狼与豺。 为:wèi(误);wéi(正)。
朝避猛虎,夕避长蛇;  
磨牙吮血,杀人如麻。 血:xuě(误);xuè(正)。
锦城虽云乐,不如早还家。  
蜀道之难难于上青天,侧身西望长咨嗟。  
顺便提一下,“噫吁嚱”有些书写作“噫吁戏”,其实是“戲”简化为“戏”后,“嚱”没有对应的简化字“口戏”造成的误用。“砯”不少书【1】写作“砅(lì)”,还有的写作“石冰”,都是不对的。
【1】如王力先生的名著《诗词格律》。相信是印刷问题。

关于汤姆孙灯问题的解释

【分类】数学 » 数学分析 | 哲学
【标签】汤姆孙灯 | 芝诺悖论 | 阿喀琉斯悖论
汤姆孙灯【1】(Thomson's Lamp)问题是 James Thomson 1954 年在 Analysis 第 15 期中提出的,文章题为 Tasks and super-tasks,也收录在 Martin GardnerAha! Gotcha: Paradoxes to Puzzle and Delight (Tools for Transformation)(《从惊讶到思考——数学悖论奇景》)第六章《超级任务》中。问题是这样描述的:
一盏灯由一个开关控制。把灯开 1 分钟,再关 ½ 分钟,再开 ¼ 分钟,再关 ⅛ 分钟,……如此进行下去。试问,两分钟后灯是开着还是关着?
许多时候,这个问题和芝诺悖论(Zeno's Paradoxes)中的阿喀琉斯悖论(Achilles and the Tortoise)联系在一起。阿喀琉斯悖论说的是古希腊神话英雄阿喀琉斯(Ἀχιλλεύς,Achilles)和乌龟赛跑,阿喀琉斯让乌龟先跑一段距离,然后从后面追赶。假定阿喀琉斯起跑时,乌龟已爬到 A。当阿喀琉斯跑到 A 时,乌龟又爬到 B,当阿喀琉斯跑到 B 时,乌龟又爬到 C,……也就是说,乌龟总是爬在阿喀琉斯前面,从而得出阿喀琉斯永远赶不上乌龟的结论。
阿喀琉斯悖论当然有违常理。级数计算表明,A, B, C, ... 组成的序列是收敛的,阿喀琉斯最终能追上乌龟。难道芝诺的推理有问题?没有!芝诺的推理逻辑是严密的,没有漏洞。那漏洞在哪呢?不少人认为芝诺的推理有一个隐含的假设,即空间的无限可分性。如果否定空间的无限可分性,那阿喀琉斯悖论就不攻自破了。我认为这种解释并不妥当,有两个原因。一是物理世界的空间是不是无限可分的,目前无从知晓;二是即使空间是无限可分的,阿喀琉斯悖论也不成立。
我们假设阿喀琉斯在 Z 处追上乌龟。如果空间是无限可分的,那么 A 和 Z 可以理解为实数轴上的两点。康托(Cantor)告诉我们,A 和 Z 之间有无穷多个点,并且这些点的个数和实数的基数一样,为 。另一方面,A, B, C, ... 也是个无穷序列,这个序列中的点的个数和自然数的基数相等,为 。这就引发了一个矛盾:芝诺试图用可数的 {A, B, C, ...} 去度量不可数的 [A, Z)。由于前者的基数比后者的小,用前者度量后者,结果只能是∞。这里的∞对应了阿喀琉斯永远赶不上乌龟。
解决了阿喀琉斯悖论,我们回到汤姆孙灯问题。汤姆孙灯问题看起来和阿喀琉斯悖论有些相似,都涉及到无穷级数求和,共同的疑惑都是到达极限和之前存在着无休止的阻尼振荡运动,这个运动不会终结,所以问题看似不可解。
这种类比也许有理,但仅仅是表面现象,汤姆孙灯问题远没有阿喀琉斯悖论深刻和复杂。实际上,汤姆孙灯问题只是一个简单的函数求值问题。我们用 f(t) 表示 t 时刻汤姆孙灯的开关状态,f(t)=1 表示开,f(t)=0 表示关。显然,原题等价于求解 f(2) 的值。f(2) 是多少,我们不知道,因为原题只给出了 f(t), t∈[0,2) 的定义。也就是说,f(2) 是没有定义的!如此而已。
我们又问,这样的话,我们就可以随意地定义 f(2) 为 0 或 1 了。那不是说,无论 f(2) 为何值,f(t) 总能依上面的开关规则过渡到 f(2)?换句话说,f(1.∞)【2】既可以为 0,也可以为 1?这不是矛盾吗?
确是如此!因为当 t=1.∞ 时,开与关的时间间隔已经减小到 0 了。既然是 0,那此时无论灯是开着还是关着,都可以在没有时间损耗的前提下切换到另一状态。f(1.∞) 的确既等于 0,又等于 1。这违反了单值函数的定义,所以 f(t) 当 t→2- 时的极限不存在。也就是 f(t) 在 t=2 附近不连续。
至此,我们得到汤姆孙灯在两分钟这个时刻:
(1) 其状态数学上无意义;
(2) 既是开着,也是关着。
两个结果任选其一,都是正确的,含义不同罢了。
对于第二个结果,也许有人会问:一盏灯怎么可能既是开着又是关着?是的,是有点超乎想象,但理论上确是可能的。如果再问:现实中这种情况也能发生吗?我想现实中不会存在这种开关不需要时间的灯。话说回来,如果这种开关出现在微观世界里,那不好说了,也许量子真有能耐改变了状态却不消耗时间。之所以这么说,因为我感觉这一概念似乎有助于解释奇异的电子双缝实验。
【1】Thomson 这个名字有四种常见的译法:汤姆逊、汤姆孙、汤姆森和汤姆生,不知哪种是标准译名。比照 Edison 译为爱迪生,Simpson 译为辛普森,Amazon 译为亚马孙(逊),似乎后缀 -son / -zon 没有固定译法。汤姆生这个译名比较少见,汤姆森更适用于 Thomsen,亚马逊已被标准化为亚马孙。因此这里我选择了个人认为最合适的汤姆孙。
【2】f(1.∞) 表示 lim f(t), t→2-

《红楼梦》中容易疏忽的血亲关系

【分类】文学 » 评论和研究 » 红楼梦
【标签】王熙凤 | 贾宝玉 | 薛宝钗 | 薛潘 | 贾元春 | 王仁
2008-6-4
我们读《红楼梦》,通常把王熙凤看作贾宝玉的堂嫂。其实从王夫人算起,王熙凤还是贾宝玉的表姐。并且,王熙凤、贾宝玉和薛宝钗三人互为表姐妹(弟)。甚至,书中看似毫不相干的王仁、薛潘和贾元春也是血缘很近的表亲。
王熙凤的父亲是谁,脂批本《红楼梦》没有交代,只在第六回指出王熙凤的父亲是王夫人的大兄。有红学爱好者找出各种证据试图证明王熙凤的父亲就是王子腾,以箬衣之见,这些证据至多算是旁证,不足为凭。目前对这个问题最好的答案大概是:无从知晓。

也谈“命”字义——与周汝昌先生商榷

【分类】文学 » 文学评论 » 红楼梦
【标签】命 | 甲戌本 | 周汝昌
邓遂夫《脂砚斋重评石头记甲戌校本》的《校后记》末页有篇周汝昌对“命”字义的“补证”文字,摘录如下:
再如第五十回《争联即景诗》,写至“黛玉忙联道:‘剪剪舞随腰。煮芋成新赏’”处,又云:“一面说,一面推宝玉,命他联。……”再到下文,叙李纨要罚宝玉作诗。湘云说有个好题目。众人问是何题目?湘云道:“命他就作《访妙玉乞红梅》,……”请看黛、湘二位,对他们的表兄,皆用“命”字。黛、湘既可于宝玉用“命”字,岂不正好说明脂砚之于雪芹亦可用“命”字乎?
我所举例,足破“(畸笏乃雪芹)长辈”论者之惑。至于所谓“靖本批语”之伪文,已有无锡、南京等处诸学者揭其内幕,故更不烦词费了。
类似的观点和论证还见于周汝昌《定是红楼梦里人》第三十二篇《奇语惊人》。
周先生的这段论证说的是一条非常有名的脂批,甲戌本第十三回《秦可卿死封龙禁尉 王熙凤协理宁国府》回后朱批云:“秦可卿淫丧天香楼,作者用史笔也。老朽因有魂托凤姐贾家后事二件,嫡是安富尊荣坐享人能想得到处;其事虽未漏,其言其意则令人悲切感服,姑赦之,因命芹溪删去。”这条批语没有署名,一般认为是畸笏叟的,理由是畸笏叟惯用“朽物”、“老朽”这样的称呼。而批语中的“芹溪”,一般也认为就是曹雪芹,因为从张宜泉的多篇诗作和小注综合起来可以得出曹雪芹号芹溪居士。当然,这还不是定论,学界有争议。我们姑且这么认为,无伤本文的讨论。
顺便提一句,许多学者认为这条脂批能够证明芹溪是《红楼梦》(或《石头记》)的作者,我对此心存疑窦。单从这条批语来看,《红楼梦》作者另有其人,芹溪只是《红楼梦》的披阅增删者也说得通。畸笏叟也许在说:“秦可卿淫丧天香楼,(原)作者用史笔也。……因命(修订此书的)芹溪删去。”并无矛盾之处。
回到原题。这条批语的语气给人的感觉是长辈在对晚辈说话,可能是由于这么几个原因:一、畸笏叟这个名字给人的感觉是年长的男子,“老朽”这一自称加强了这种印象;二、“赦”给人以权力感,往往当权者才有资格赦免有过错者(意指秦可卿的原型);三、“命”是居高临下的口气,长辈对晚辈可以命令。于是,不少学者从这“命”字推断出畸笏叟是曹雪芹的长辈。而上面引用的周先生的补证正是反驳这种观点。周先生从《红楼梦》内寻找依据,证明“命”可以用于平辈间,且不分年长年幼。另外,同一书中,周先生还提到《红楼梦》中有凤姐“令”贾琏如何如何的例子,目的是由“令”及“命”,曲线支持他的观点。
我认为周先生论证的方法是对的,但选取的证据却不对。以我的理解,“命”字不一定非用于长辈对晚辈,但一般用于地位高者对地位低者。换句话说,“命”字包含两重含义:一、施者无需征得受者同意而提出要求;二、受者通常不能拒绝施者的要求。这里的要求可以是合情理的,也可以是不合情理的。这里,我们把问题简化一下,来看看《红楼梦》中哪些人可以“命”宝玉做这做那。
一、直系长辈,有贾母、贾政和王夫人,他们可以“命”宝玉,无可厚非。第二十九回:“贾母听说,便命宝玉摘下通灵玉来,放在盘内。”第十七回:“贾政拈髯寻思,因抬头见宝玉侍侧,便笑命他也拟一个来。”旁系长辈呢?道理上也可以,但出于礼节和权力制度上的不宜越权,一般不会这么做。
二、年长的直系平辈,即元春。元春既是贵妃,又是宝玉的亲姐姐,还是宝玉的启蒙老师,自然也可以“命”宝玉。第十八回:“元妃等起身,命宝玉导引,遂同诸人步至园门前。”
三、关系好的年长平辈,如凤姐、贾珍。关系好则禁忌少,所以说话行事不拘束。第十三回:“贾珍便忙向袖中取了宁国府对牌出来,命宝玉送与凤姐,……”第十五回:“一时凤姐进入茅堂,因命宝玉等先出去顽顽。”
四、未出嫁的姊姊妹妹,指黛玉、宝钗和湘云。黛玉和宝玉内心深处早已视对方为终身伴侣,宝钗年纪比宝玉大又懂事,湘云活泼爽直有才情,她们对宝玉都有精神优势,可以自然地“命”他做事。尤其在玩笑的场合,更不必“锦心绣口”,如上文周先生引用的例子。而宝玉呢,和这些姊姊妹妹在一起时,向来处在下风,常常被支使得不亦乐乎却又乐此不疲。其他姊妹,如迎春,她的性格和与宝玉的亲近程度决定了她不会命令宝玉。而探春、惜春比宝玉小,又不象湘云那样直肠子,所以也不会这么做。特别是探春,对宝玉这个哥哥还十分亲密敬重,这从第三十七回邀宝玉结海棠诗社帖可知一二。
五、关系好的丫鬟,如香菱。宝玉不但会被姊姊妹妹欺负,甚至常受丫鬟们的气,第三十五回傅秋芳家两个嬷嬷的对话明明白白地指出这一点。也正因为宝玉对女孩儿百般怜爱敬重,以香菱的温柔谨慎,面对宝玉也有心理优越感。第六十二回:“(香菱)说着,接了裙子,展开一看,果然同自己的一样。又命宝玉背过脸去,自己叉手向内解下来,将这条系上。”如果换了薛潘,她敢“命”吗?其他的丫鬟,象晴雯,道理上也是可能这么做的,只是没有合适的场景表现罢了。
以上罗列了《红楼梦》中“命”字使用的几种场合,可以说和现代汉语的“命”字义没有差别——“命”字是优势地位者对劣势地位者行使权力的表达。周先生引用的例子不能证明“命”字在写作《红楼梦》的年代也适用于地位相当的人群间。再有,畸笏叟的这条批语严肃深沉,不是玩笑语,也不是随意点评。以这里的“命”字义判断,畸笏叟确当地位高于曹雪芹,可能是长辈,可能是年长的平辈,或是曹雪芹也如贾宝玉一般视女儿为水做的骨肉,那畸笏叟是他敬爱的女孩儿也未可知。
最后,由“令”及“命”的推理,逻辑上也有问题。“令”和“命”在字意上并不完全相同,“令”的语气可以比“命”轻,有“使”、“让”的意思,适用的场合相对较广。第十六回:“一时贾琏的乳母赵嬷嬷走来,贾琏与凤姐忙让他一同吃酒,令其上炕去。赵嬷执意不肯。”这里的“令”无论如何不会是命令的意思。

哈泽德的难题

【摘要】本文给出了哈泽德覆面算题的解,并用计算机验证该结果。
【分类】数学 » 算术 | 数学 » 数学游戏
【标签】覆面算题 | Martin Gardner
2008-8-6
下面的乘法算式题(Cryptarithm Multiplication Problem)来自 Harry Hazard,收录于 Scientific American(《科学美国人》)著名专栏作家 Martin Gardner(马丁·加德纳)主持的 Mathematical Games 1967 年的结集出版物 Numerology of Dr. Matrix。该书 1976 年再版时扩充并更名为 The Incredible Dr. Matrix,1985 年再次扩充并更名为 The Magic Numbers of Dr. Matrix
LYNDON
×
B
JOHNSON
算式中,相同的字母代表相同的数字,不同的字母代表不同的数字。
这道题有几个新巧的地方。首先,它在题面上嵌入了美国总统 Lyndon Baines Johnson(林登·贝恩斯·约翰逊)的名字;其次,从命题到解答,它仅仅涉及非常浅显的算术知识,但这并不意味着求解过程也同样简单。实际上,整个求解过程颇为繁琐;最后,更加难得的是,它竟然有唯一的答案,这多少有些出人意表。
我们来试着解决这个问题。
1 已知:b,d,h,j,l,n,o,s,y 为互不相等的整数,且 0≤b,d,h,j,l,n,o,s,y≤9。
2 显然,b≠0,1,即 b≥2。否则,算式不成立。
3 我们从低位开始依次建立等式。
3.1 考虑算式的最末位,有:nb=10x1+n,即 n(b-1)=10x1。因为 0≤n≤9,b≥2,n≠b,所以 (n,b) 可能的取值为 (0,2), (0,3), (0,4), (0,5), (0,6), (0,7), (0,8), (0,9), (2,6), (5,3), (4,6), (5,7), (5,9), (8,6)。
3.2 考虑算式的末两位,有:(10o+n)b=100x2+10o+n,即 (10o+n)(b-1)=100x2
3.2.1 若 n=0,则 10o(b-1)=100x2,即 o(b-1)=10x2。由 0≤o≤9,o≠n 得,(o,b) 可能的取值为 (2,6), (5,3), (4,6), (5,7), (5,9), (8,6)。即 (o,n,b) 可能的取值为 (2,0,6), (5,0,3), (4,0,6), (5,0,7), (5,0,9), (8,0,6)。
3.2.2 若 b=6,则 (10o+n)×5=100x2,即 10o+n=20x2。由此可知 10|n,因为 0≤n≤9,所以 n=0。见 3.2.1
3.2.3 若 n=5,则 (10o+5)(b-1)=100x2,即 (2o+1)(b-1)=20x2。因为 2o+1 为奇数,所以 4|b-1。由 b≥2,b≠n 知 b=9。从而,o=2 或 7。即 (o,n,b) 可能的取值为 (2,5,9), (7,5,9)。
综合 3.2.13.2.23.2.3 得,(o,n,b) 可能的取值为 (2,0,6), (5,0,3), (4,0,6), (5,0,7), (5,0,9), (8,0,6), (2,5,9), (7,5,9)。
3.3 考虑算式的末四位,有:(1000n+100d+10o+n)b=10000x3+1000n+100s+10o+n,即 100db+(1001n+10o)(b-1)=10000x3+100s。
3.3.1 若 n=0,则 100db+10o(b-1)=10000x3+100s,即 db+o(b-1)/10=100x3+s,即 100|db+o(b-1)/10-s。因为 db+o(b-1)/10-s<100,所以 db+o(b-1)/10-s=0。
3.3.1.1 若 (o,b)=(2,6),则 6d+1-s=0。因为 d≠n,所以 d≠0,从而 d=1,s=7。即 (d,s,o,n,b) 可能的取值为 (1,7,2,0,6)。
3.3.1.2 若 (o,b)=(5,3),则 3d+1-s=0。因为 d≠n,所以 d≠0,从而 d=1,s=4 或 d=2,s=7。即 (d,s,o,n,b) 可能的取值为 (1,4,5,0,3), (2,7,5,0,3)。
3.3.1.3 若 (o,b)=(4,6),则 6d+2-s=0。因为 d≠n,所以 d≠0,从而 d=1,s=8。(d,s,o,n,b) 可能的取值为 (1,8,4,0,6)。
3.3.1.4 若 (o,b)=(5,7),则 7d+3-s=0。因为 d≠n,所以 d≠0。无解。
3.3.1.5 若 (o,b)=(5,9),则 9d+4-s=0。因为 d≠n,所以 d≠0。无解。
3.3.1.6 若 (o,b)=(8,6),则 6d+4-s=0。因为 d≠n,所以 d≠0。无解。
3.3.2 若 (n,b)=(5,9),则 900d+8(5005+10o)=10000x3+100s,即 90d+4004+8o=1000x3+10s,即 100|9d+(2002+4o)/5-s。
3.3.2.1 若 o=2,则 100|9d+402-s。因为 393≤9d+402-s≤483,所以 9d+402-s=400,即 9d+2-s=0。因为 s≠o,所以 s≠2。无解。
3.3.2.2 若 o=7,则 100|9d+406-s。因为 397≤9d+406-s≤487,所以 9d+406-s=400,即 9d+6-s=0。从而 d=0,s=6。即 (d,s,o,n,b) 可能的取值为 (0,6,7,5,9)。
综合 3.3.13.3.2 得,(d,s,o,n,b) 可能的取值为 (1,7,2,0,6), (1,4,5,0,3), (2,7,5,0,3), (1,8,4,0,6), (0,6,7,5,9)。
3.4 考虑算式的末五位,有:(10000y+1000n+100d+10o+n)b=100000x4+10000h+1000n+100s+10o+n,即 10000yb+100db+(1001n+10o)(b-1)=100000x4+10000h+100s。
3.4.1 若 n=0,则 10000yb+100db+10o(b-1)=100000x4+10000h+100s,即 yb+(db+o(b-1)/10-s)/100=10x4+h。由 3.3.1 知 db+o(b-1)/10-s=0,所以 10|yb-h。
3.4.1.1 若 b=6,则 10|6y-h。
3.4.1.1.1 若 (d,s,o)=(1,7,2),因为 y≠b,y≠s,h≠n,y≠h,所以 (y,h) 可能的取值为 (3,8), (9,4)。即 (y,h,d,s,o,n,b) 可能的取值为 (3,8,1,7,2,0,6), (9,4,1,7,2,0,6)。
3.4.1.1.2 若 (d,s,o)=(1,8,4),因为 y≠d,h≠s,h≠o,h≠n,y≠h,所以 (y,h) 可能的取值为 (7,2)。即 (y,h,d,s,o,n,b) 可能的取值为 (7,2,1,8,4,0,6)。
3.4.1.2 若 b=3,则 10|3y-h。
3.4.1.2.1 若 (d,s,o)=(1,4,5),因为 y≠b,y≠s,h≠b,h≠d,h≠s,y≠h,所以 (y,h) 可能的取值为 (2,6), (6,8), (9,7)。即 (y,h,d,s,o,n,b) 可能的取值为 (2,6,1,4,5,0,3), (6,8,1,4,5,0,3), (9,7,1,4,5,0,3)。
3.4.1.2.2 若 (d,s,o)=(2,7,5),因为 y≠b,y≠d,y≠s,h≠b,h≠d,h≠s,y≠h,所以 (y,h) 可能的取值为 (6,8), (8,4)。即 (y,h,d,s,o,n,b) 可能的取值为 (6,8,2,7,5,0,3), (8,4,2,7,5,0,3)。
3.4.2 若 (d,s,o,n,b)=(0,6,7,5,9),则 9y+4=10x4+h。即 10|9y+4-h。因为 y≠d,y≠s,y≠n,h≠d,h≠s,h≠n,y≠h,所以 (y,h) 可能的取值为 (1,3), (3,1)。即 (y,h,d,s,o,n,b) 可能的取值为 (1,3,0,6,7,5,9), (3,1,0,6,7,5,9)。
综合 3.4.13.4.2 得,(y,h,d,s,o,n,b) 可能的取值为 (3,8,1,7,2,0,6), (9,4,1,7,2,0,6), (7,2,1,8,4,0,6), (2,6,1,4,5,0,3), (6,8,1,4,5,0,3), (9,7,1,4,5,0,3), (6,8,2,7,5,0,3), (8,4,2,7,5,0,3), (1,3,0,6,7,5,9), (3,1,0,6,7,5,9)。
3.5 考虑整个算式,有:(100000l+10000y+1000n+100d+10o+n)b=1000000j+100000o+10000h+1000n+100s+10o+n,即 100000lb+10000yb+100db+(1001n+10o)(b-1)=1000000j+100000o+10000h+100s。
3.5.1 若 (y,h,d,s,o,n,b)=(3,8,1,7,2,0,6),则 6l=10j+1。因为左式为偶,右式为奇,所以无解。
3.5.2 若 (y,h,d,s,o,n,b)=(9,4,1,7,2,0,6),则 6l=10j-3,因为左式为偶,右式为奇,所以无解。
3.5.3 若 (y,h,d,s,o,n,b)=(7,2,1,8,4,0,6),则 6l=10j。因为 l≠j,所以 (l,j) 可能的取值为 (5,3)。即 (l,j,y,h,d,s,o,n,b)=(5,3,7,2,1,8,4,0,6)。
3.5.4 若 (y,h,d,s,o,n,b)=(2,6,1,4,5,0,3),则 3l=10j+5,即 l=5,j=1。因为 l≠o,所以无解。
3.5.5 若 (y,h,d,s,o,n,b)=(6,8,1,4,5,0,3),则 3l=10j+4,即 l=8,j=2。因为 l≠h,所以无解。
3.5.6 若 (y,h,d,s,o,n,b)=(9,7,1,4,5,0,3),则 3l=10j+3,即 l=1,j=0。因为 l≠d,所以无解。
3.5.7 若 (y,h,d,s,o,n,b)=(6,8,2,7,5,0,3),则 3l=10j+4,即 l=8,j=2。因为 l≠h,所以无解。
3.5.8 若 (y,h,d,s,o,n,b)=(8,4,2,7,5,0,3),则 3l=10j+3,即 l=1,j=0。因为 j≠n,所以无解。
3.5.9 若 (y,h,d,s,o,n,b)=(1,3,0,6,7,5,9),则 9l=10j+6,即 l=4,j=3。因为 j≠h,所以无解。
3.5.10 若 (y,h,d,s,o,n,b)=(3,1,0,6,7,5,9),则 9l=10j+4,即 l=6,j=5。因为 l≠s,所以无解。
综合 3.5.13.5.10 可知,本题有唯一解 (l,j,y,h,d,s,o,n,b)=(5,3,7,2,1,8,4,0,6),即:
570140
×
6
3420840
❏验证程序
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Hazard.py - Hazard's Problem
# Copyright © 2008 Roy Fang <royfang@hotmail.com>. All rights reserved.
l = 10
a = range(l)
def permute(n):
    if n > 1:
        for i in range(n):
            if i > 0:
                m = n - 1 if n == 2 or n % 2 else i - (i == n - 1)
                a[-n], a[-m] = a[-m], a[-n]
            permute(n - 1)
    else:
        atoi = lambda *s: reduce(lambda x, y: x * 10 + y, s)
        p = atoi(a[0], a[1], a[2], a[3], a[4], a[2])
        q = a[5]
        r = atoi(a[6], a[4], a[7], a[2], a[8], a[4], a[2])