旧闻一则:神秘的0x5f3759df 不可思议的Quake III源码

    Quake III公开源码后,有人在game/code/q_math.c里发现了这样一段代码。它的作用是将一个数开平方并取倒,经测试这段代码比(float)(1.0/sqrt(x))快4倍:
float Q_rsqrt( float number )
{
  long i;
  float x2, y;
  const float threehalfs = 1.5F;

  x2 = number * 0.5F;
  y  = number;
  i  = * ( long * ) &y;  // evil floating point bit level hacking
  i  = 0x5f3759df - ( i >> 1 ); // what the fuck?
  y  = * ( float * ) &i;
  y  = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
  // y  = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed

  #ifndef Q3_VM
  #ifdef __linux__
    assert( !isnan(y) ); // bk010122 - FPE?
  #endif
  #endif
  return y;
}

    code/common/cm_trace.c中也出现了这样一段解释sqrt(x)的函数,与上面的代码唯一不同的就是这个函数返回的是number*y:
/*
================
SquareRootFloat
================
*/
float SquareRootFloat(float number) {
    long i;
    float x, y;
    const float f = 1.5F;

    x = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;
    i  = 0x5f3759df - ( i >> 1 );
    y  = * ( float * ) &i;
    y  = y * ( f - ( x * y * y ) );
    y  = y * ( f - ( x * y * y ) );
    return number * y;
}

    这样的代码速度肯定飞快,我就不用多说了;但算法的原理是什么呢?其实说穿了也不是很神,程序首先猜测了一个接近1/sqrt(number)的值,然后两次使用牛顿迭代法进行迭代。根号a的倒数实际上就是方程1/x^2 – a = 0的一个正实根,它的导数是-2/x^3。运用牛顿迭代公式x' = x – f(x)/f'(x),式子化简为x' = x * (1.5 – 0.5a * x^2)。迭代几次后,x的值将趋于1/sqrt(a)。
    但这段代码真正牛B的是那个神秘的0x5f3759df,因为0x5f3759df – (i >> 1)出人意料地接近根号y的倒数。人们都不知道这个神秘的常数是怎么来的,只能把它当作神来膜拜。这个富有传奇色彩的常数到底咋回事,很少有人说得清楚。这篇论文比较科学地解释了这个常数。

Chain Factor:容易上瘾的Flash解谜小游戏

    Numb3rs是一部很有意思的美剧,讲述一个应用数学家利用数学模型帮助FBI破案。在最近的一集Numb3rs中,一家网游公司在现实世界里精心策划了一次大型的解谜寻宝活动,而将一部分线索隐藏在网络游戏中,以此来推广自己的游戏;但不幸的是网游中的帮派斗争转移到了现实社会中,游戏者在真实世界里被害。
    故事多次提到一个叫做Chain Factor的解谜游戏。这是一个非常有创意的消除类小游戏,任意时刻一旦某个小球身上的数字与它所在行或所在列里(连续的)小球的个数相同,这个小球就会被消去。灰色的球实质上是穿了两层衣服的普通球,只要它四周有小球被消除了,它就会掉一层皮。
    游戏很有挑战性。每过一段时间棋盘最底层会冒出一排灰色球,它们出现时间的间隔将越来越短,最终总会Game Over。你可以提交你的最高分,每天的最高分和历史最高分都将在首页显示出来。另一个有趣的挑战便是,是否有人能够把整个棋盘清空。目前我的Basic Mode最高分是140 818。你呢?

    另外,提到这一集的Numb3rs,前几天我发现了另一件有趣的事情,现实生活中还真有这样的解谜寻宝活动。这个月30日,在伦敦将有一场名为The London Code的解谜竞赛,任何人都可以发一封邮件到官方网站免费报名,比赛开始时所有报名的人都会收到一封含有解谜线索的电子邮件。就像探险小说一样,这些线索将带着比赛者穿越伦敦城市到处进行探索,寻找一个又一个的提示信息。当最终获胜者产生后,每个玩家都会再收到一封邮件宣布比赛结束。这里有一个活动的宣传片。

网站推荐:blackflip 基于Flash的web 2.0解谜游戏站

    blackflip是一个有趣的智力游戏。在每一个关卡里,你需要画一条不自交的路线,这条路线经过的所有格子都将会反色,游戏的目标就是要让反色后同一行的所有格子恰好都同色。游戏规则很简单,但有一些关卡特别费脑子。我很喜欢这个游戏的一个Tagline:Waste Time and Get Smarter。
    与其它Flash解谜游戏不同的是,这是一个完整的web 2.0应用。这个网站会记录你曾玩过的关卡,并能告诉你哪些关卡你解开过,哪些关卡你最终放弃了。破解一道关卡后你还可以为该关卡评分留言,系统将依据这个评分来确定关卡的难度系数。任何人都可以为这个游戏创造新的关卡,然后与朋友分享自己创造的关卡。目前该网站的总关卡数已经达到3000多个;更牛B的是,该网站甚至还提供了新关卡的RSS输出!

Eleusis Express:非常有创意的多人纸牌游戏

    1956年Robert Abbott发明了一个全新的纸牌游戏叫做Eleusis,后来Martin Gardner在1959年6月的Scientific American杂志上介绍了这个游戏。77年10月这个游戏又进一步得到完善,并发展出一些其它的玩法。最近,John Golden提出了这个游戏的第三个版本Eleusis Express,他比Eleusis更简单,更完备,平均游戏时间也更短。Robert Abbott对这个游戏非常满意,这种简单而有趣的推理游戏很可能会像杀人游戏一样流行起来。下面我简单介绍一下这个游戏的规则,你将会看到一种集策略和推理于一体的全新的纸牌游戏。

    这个游戏的规则极其简单,但变化也异常丰富,因为这个游戏的出牌方式是不固定的,游戏开始时玩家甚至不知道出牌的规则是什么。玩家的主要任务就是在游戏过程中探索出牌的规则。游戏需要两副牌,玩家以3到8人为宜。每轮游戏前,玩家需要推选出一位主持人,主持人在这个游戏里扮演最重要的角色。游戏开始前,主持人自己在心里默想一个出牌规则(Secret Rule),但不能告诉玩家。规则的内容应该只考虑扑克牌的花色与点数,与出牌人、牌的摆放方式等无关。这个规则必须简单、明确,通常以“如果上一张牌是什么什么,那么下一张牌就该接什么什么”一类的形式给出,比如“如果上一张牌是红色,下一张牌就是黑色;如果上一张牌是黑色,下一张牌就该是红色”,或者是“要么与前一张牌同花色,要么与前一张牌同点数”。然后主持人洗牌,给每个人发12张牌,然后再翻出一张放在桌面上作为第一张牌打出。这张牌及后面正确的跟牌都摆成一行,叫做主线(Mainline);主线下方可能会有若干边线(Sideline),表示错误的跟牌。游戏正式开始前,主持人可以对秘密规则进行一些提示,之后玩家轮流打牌,主持人判断玩家打出的牌是否符合他的规则:

    
如果打出的牌符合规则
    此时主持人把这张牌加在主线的右边,该玩家手中的牌就少了一张。如果此时该玩家手中的牌打完了,则游戏结束,否则游戏继续进行。
    另外,该玩家还可以获得一次猜测出牌规则的机会,同时每个玩家都必须听他说的答案。如果该玩家猜对了,主持人也宣布游戏结束,否则游戏继续。
如果打出的牌不符合规则
    此时主持人把这张牌放在的相应的边线位置上,告诉大家这张牌不能接在这个位置。这名玩家需要再摸一张牌,手中的牌的张数不变。

    轮到某位玩家出牌时,该玩家可以选择不出牌,即宣称自己无牌可打。此时他应该把手中的牌摊出来给所有人看,同时主持人判定该玩家是否确实无牌可打:
如果该玩家确实无牌可打
    如果此时玩家手中只有一张牌,游戏结束。否则,主持人清点该玩家手中牌的数目N,把它们放回还没发完的牌摞的最底下,再发给他N-1张牌。同时,该玩家获得一次猜测出牌规则的机会,猜对了同样可以直接获胜。
如果该玩家有可以打的牌
    此时主持人从中选出一张可以打的牌接在主线后面,该玩家收起自己其余的牌并再摸一张,保持手中的牌数不变。

    游戏结束后,每个人的得分就是自己打出去的牌的张数。打完所有牌而获胜的玩家再获3分的加分,猜对规则而获胜则得到6分的加分。主持人的得分与本轮最高分相同。然后大家重新推选主持人,继续下一轮游戏。
    如果牌抓完了但游戏还没结束,可以再洗一副牌继续进行,或宣布游戏结束,本轮不计分。然后,主持人阴笑几下,故弄玄虚地说出自己所想的规则,等待玩家们恍然大悟并集体发出“哎呀~~~”的叹息声(或者等待玩家大骂这规则太他妈BT了谁能想到啊)。
    若干轮游戏后,最终的胜者就是累积得分最高的人。我们可以适当给赢家一些奖励,比如让他亲一下最漂亮的MM玩家,或者传几个小A给他。得分最低的人也应当受到惩罚,比如叫他把MM共享出来让大家玩弄,或者贡献一个XX论坛的账号。

    能想到一个简单明了而又富有新意的规则是非常重要的,因此游戏的主持人是整个游戏的灵魂,一个思维活跃又爱捉弄人的主持人可以让游戏变得非常精彩。这里写一些自己想到的规则,大家有什么好的想法也可以在下面说一说。

  • 按黑红梅方的顺序出牌
  • 按三张红色,三张黑色,又三张红色,又三张黑色的顺序出牌
  • 如果上一张牌的点数是1到7,则应该接8到K;如果上一张牌是8到K,则应该接1-7
  • 相邻两张牌的点数之和大于10
  • 相邻两张牌的点数的差的绝对值不超过3
  • 相邻两张牌的点数加起来能被3整除
  • 下一张牌的点数比上一张牌大1点、2点、3点或4点;数字大小关系是“循环的”
  • 如果上一张牌的点数是奇数,则出红色牌;如果上一张牌的点数是偶数,则出黑色牌
  • 如果上一张牌是红色,则出牌的点数小于等于上张牌的点数;否则,出牌的点数大于等于上张牌的点数
  • 如果上一张牌的点数为平方数,则出牌的点数是非完全平方数;否则出牌的点数应该是一个平方数
  • 牌的点数一大一小交替排列(即奇数位置上的牌比前面的点数小,偶数位置上的牌比前面点数大)
  • 如果花色与前面一张相同,则点数必须比它大;如果花色与前面一张不同,则点数必须比它小

做人要厚道 转贴请注明出处
查看更多:http://www.logicmazes.com/games/eleusis/index.html

网站推荐:The Python Challenge 第一个编程解谜站点

    The Python Challenge是一个过关式的解谜站点,使用的是经典在线解谜站点Not Pr0n的模式:根据提示找出下一关的网页地址。和Not Pr0n不同的是,在每一关里你都需要编写程序来寻找答案。虽然这个解谜站点的名字叫做Python Challenge,但事实上你可以使用任意一种程序语言(除了少数一两关可能会用到点Python的知识)。
    虽然这个解谜站点已经很火星了(05年建立的),但在国内似乎流传得并不广。偶然发现这个站点,想到NOIp也快到了,多一个有趣的coding练习也是一件好事,因此这里推荐一下这个站点,大家可以一起来试试。

本日志评论原则:禁止“剧透”