开发者生态
morning
转弯比弧度更好 (2022)
2026-08-20
1 阅读
约6分钟阅读
mayoff
字号:
不久前,人们花了很多努力说服人们用“tau”的近似值(6.28318...)代替“pi”的近似值(3.14159...)。根据大量博客文章和 YouTube 视频,这个想法是,常见的公式变得更简单,并且更容易使用描述整个圆而不是半圆的常数。一般来说,我同意。虽然这是一个小问题,但值得一提。如果将 pi 替换为 tau,大多数代码确实会稍微好一点。然而,在所有的宣传中,一个更有影响力的机会却被忽视了。大多数情况下,可以完全删除 pi ,而不是用 tau 替换 pi 。首先,考虑代码中 pi 和 tau 的常见情况:将事物与弧度相互转换以调用三角函数。如果您曾经使用过这些常量,那么您编写的绝大多数内容可能都是这样的: y = center.y + (center.y * Math::sin(h * Math_TAU) * s) - (cursor->get_height() / 2);这不是我构建一个示例,而是我在 github 上随机打开 Godot 引擎的源代码并搜索“tau”。上面的一段代码以及数十个类似的用法就是出现的结果。戈多在这里并没有什么特别之处。如果您打开任何随机游戏引擎代码库,您可以进行完全相同的搜索并看到完全相同的用法。注意这里发生的事情:程序员有一个值 h,它已经是 0 到 1 范围内的周期性值,但它们乘以 tau,因为它们需要调用 sin。就您看来,这似乎非常明智。但罪的实施又如何呢? sin 有很多实现,但无论你看哪一种,在函数入口点附近你都会看到类似这样的东西: _PS256_CONST(cephes_FOPI, 1.27323954473516); ... y = _mm256_mul_ps(x, *(v8sf*)_ps256_cephes_FOPI);再说一遍,这不是我编造的例子 - 这是来自这个经常引用的 sin 的 AVX2 实现。这并不罕见或奇怪——几乎每个快速三角库都会做一些非常相似的事情。这条线有什么作用?它将输入乘以常数 1.27323954473516。恰好是 4/pi 。因此,调用代码正在执行以下操作:sin(h * 2 * pi),但库代码立即执行此操作:y = (4 / pi) * x,这意味着调用代码乘以 pi 因子,以便库代码可以立即将其再次除掉。从字面上看,这就是无缘无故地来回转换弧度。如果两个程序员都同意不使用弧度,而是使用 h 已经存在的原始 [0, 1] 域,那么他们的工作都会变得更简单:调用者保存一个乘法,而库得到一个更容易理解的精确常量。而“精确”的部分其实很有趣。当你错误地转换为弧度时,你不仅需要支付额外的乘法费用,而且值得注意的是,除了 0 之外的所有常见弧度角都很难表示。想要以弧度形式存储 90 度?无论您使用多少位,它都永远不会准确。然而,[0, 1] 上的 90 度仅为 0.25 - 这种位模式甚至根本不需要任何尾数! 0.5?相同的! 0.75?只需要一位尾数即可准确表示。因此,[0, 1]范围不仅比弧度计算效率更高,而且在表示实际使用中经常出现的典型值时也更加紧凑和精确。我可以理解为什么有些人会担心做出这种转变。即使你相信我所有的用户端代码都会乘以 pi 或 tau,并且所有库端代码都会将其除掉,你仍然可能会有那种沉闷的“数学类感觉”,如果你停止使用弧度,你就会做错事。但数学从未规定正弦和余弦必须采用弧度参数!将圆参数化为从 0 到 1,而不是从 0 到 tau 的想法并不是我在这篇博文中随意提出的想法。它实际上是一个合法的、现有的数学构造,它甚至还有一个名字:它称为“转”。依次类推,0 为 0 度,0.5 为 180 度,1 为 360 度,2 为 720 度,依此类推。这正是我们想要的。因此,如果您担心数学老师会生您的气,则无需担心。只需告诉他们您仔细考虑了这个问题,并决定以轮数而不是弧度来参数化角度是解决当前问题的最有效方法!如果您编写了自己的数学库,或者将其他人的数学库复制到您的项目中,那么希望您很清楚如何摆脱弧度并从代码库中消除 pi 和 tau。您所要做的就是采用 sin 和 cos 函数并让它们轮流而不是弧度,这通常只需要快速调整单个常数即可。如果您想支持旧代码,请为新的回合制三角函数选择不同的名称。然后,对于遗留代码,您仍然可以通过创建这些例程来支持旧的基于弧度的 sin 和 cos
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱