二代码优化(有哪些令人拍案叫绝的代码优化)

二代码优化(有哪些令人拍案叫绝的代码优化)

adminqwq 2026-02-13 社会资讯 12 次浏览 0个评论

1999年,《雷神之锤3》发布。画质炸裂,但奇怪的是,破电脑也能跑得很流畅。

二代码优化(有哪些令人拍案叫绝的代码优化)
(图片来源网络,侵删)

几年后源代码开源,全世界程序员冲进去扒拉,想看看id Software到底用了什么黑科技。然后大家就发现了这么一段东西:

float Q_rsqrt(float number) { long i; float x2, y; const float threehalfs = 1.5F; x2 = number * 0.5F; y = number; i = *(long*)&y; i = 0x5f3759df - (i >> 1); // what the fuck? y = *(float*)&i; y = y * (threehalfs - (x2 * y * y)); return y;}

我当时看完这段代码,愣了好一会儿。

这函数干嘛的?算 1/√x,平方根的倒数。

你可能会问,这有啥难的,调个sqrt再除一下不就行了?

问题是,那个年代CPU算浮点开方慢得要死,一次要几十上百个时钟周期。而3D游戏里算光照、算反射,每帧要归一化几万个向量,每次都要求这玩意儿。按正常写法,直接卡成幻灯片。

然后就有人整出了上面这段代码。

核心就一行:i = 0x5f3759df - (i >> 1)

看到这你肯定懵逼——把浮点数的二进制当整数读出来,右移一位,再用一个莫名其妙的常数去减它,结果居然就是平方根倒数的近似值???

这不是玄学,是数学。让我给你掰扯清楚。

首先你得知道浮点数在内存里长啥样。

一个32位float,内存里分三块:1位符号、8位指数、23位尾数。表示的值是:

(1 + 尾数/2²³) × 2^(指数-127)

比如8.0,就是 1.0 × 2³,指数存130(就是3+127),尾数存0。

现在来个骚操作:把这个浮点数的二进制直接当整数读出来。

你会得到一个整数 I = 指数×2²³ + 尾数。

关键来了。

浮点数的真实值取个对数,大概是:log₂(value) ≈ I/2²³ - 127

换句话说,浮点数的"整数形式"和它的对数基本成正比。

这个性质太重要了。因为我们要算的是 y = x^(-0.5),取对数就是 log(y) = -0.5 × log(x)。

对数之间是线性关系!那我直接用整数运算不就能算对数运算了吗?

具体推一下。设 Ix 是 x 的整数表示,Iy 是 y 的整数表示:

Iy/2²³ - 127 ≈ -0.5 × (Ix/2²³ - 127)

解出来:

Iy ≈ 1.5 × 127 × 2²³ - 0.5 × Ix ≈ 0x5f400000 - (Ix >> 1)

诶,算出来是 0x5f400000,但代码里用的是 0x5f3759df,咋回事?

因为上面的推导有近似误差。0x5f3759df 是有人通过数值方法调出来的,能让最大误差最小。后来有数学家专门写论文算过,理论最优值是 0x5f375a86,跟这个就差一丢丢。

到这里,我们就用一次整数减法和一次移位,搞出了一个粗糙的近似值。

但粗糙不够用啊,游戏还是会穿帮。

所以最后还有一步:牛顿迭代。

牛顿迭代是个老套路了,用来逼近方程的根。对于 y = 1/√x 这个问题,迭代公式是:

y = y × (1.5 - 0.5 × x × y²)

就是代码最后那行。跑一次迭代,精度直接从1%提到0.1%左右,够用了。

整个过程,没调任何数学库,就几次整数运算加几次浮点乘法,速度比老实调 sqrt 快了四五倍。在那个年代,这就是流畅和卡顿的区别。

这段代码牛在哪?

它把IEEE 754浮点数表示的特性、对数运算的数学性质、还有牛顿迭代这些东西,全揉在一起,写出了一个看起来像黑魔法但其实每一步都有道理的算法。

这需要你真正理解计算机是怎么存数字的,而不只是会调API。

至于作者是谁,到现在也没完全搞清楚。本来以为是John Carmack写的,但他自己否认了。有人说可能是90年代SGI的某个图形学大佬,但查无实据。

不过说实话,现在这代码没啥实用价值了。现代CPU有专门的指令干这事,比什么软件算法都快。

但它已经变成了一个符号。每次有人问"你见过最牛的代码是啥",我第一个想到的就是它。

它告诉你,编程这事,有时候不是比谁API背得熟,是比谁对底层的理解更深。

你们还见过啥让你直接愣住的代码?

转载请注明来自海坡下载,本文标题:《二代码优化(有哪些令人拍案叫绝的代码优化)》

每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,12人围观)参与讨论

还没有评论,来说两句吧...