提问者:小点点

调整数学/计算精度以提高计算效率,包括三角函数 // 最佳 2D 碰撞算法 [已关闭]


想改进这个问题吗?通过编辑这篇文章来更新问题,使其仅关注一个问题。

我有一些关于在计算和cpu架构上节省计算能力的问题,因为我想和朋友一起创建一个2d游戏,可以处理尽可能多的对象和参数来学习高效计算。我们目前正在使用py游戏,但可以实现c和f的函数。

所以:

1.你能通过降低商的除法或二元位的精度来节省处理能力吗?

这个精度必须是c的二进制小数位,因为例如,十进制中的0.1在二进制中的逗号后面有一个重复的小数部分,所以假设您将其设置为0.125,即二进制中的0.001=3个小数位。我的意思是,你可以使用长除法来获得某个分数位,但我想这不会更有效,因为处理器必须再次将每个中间结果加载到寄存器中。我无法理解这一点,因为x86处理器在4个不同版本中都有自己的DIV指令,我不知道cpu是如何执行这些指令的。是否可以编写一个采用精度参数的汇编函数来提高效率?如果不需要2048以上的精度,那么只使用半精度浮点或其他数据类型是否有用
另一方面,减少像PI这样的常数的二进制位是有用的,它可以在一帧中使用数千次,因为在木星轨道之后,我不需要英寸精度,标准的小数点是15位。

2. 降低三角函数精度或使用数据表

我听说CORDIC alghorithm是一位一位地进行运算的,那么你能给出二进制位数来计算的版本会更有效吗?我不知道pyhton math默认使用哪种算法,也不知道numpy/anaconda之类的软件中是否有类似的算法。或者,根据所需精度预先计算sin函数结果表,或者在需要更多结果时在这些结果之间进行插值,会更快。

3.你知道的最有效的碰撞算法是什么?

我有一个想法,而不是检查对象对对象,最终以检查中对象的平方数结束,你可以将对象的位置写入一个矩阵(Numpy数组),该矩阵具有你可以设置的精度,所以对于2d来说,它可能是像素完美的,然后取决于你的游戏区域有多大,例如1920*1080矩阵为1个屏幕。然后矩阵中的位置只是保存一个引用对象池中对象的数字。当你在移动时写下你的新位置时,你只需检查是否有东西已经在那里。这也有一个优点,即位图碰撞与矩形碰撞相比,额外的成本为0,因为你可以像那样把它写入矩阵。我可以想象这在大量对象上运行得更有效,我得到了这个工作的基本版本,但需要更多的优化。我知道你也可以对对象进行空间细分,但我不知道这会产生更好的结果。

最后,您是否有任何书籍推荐,有助于了解处理器如何进行操作并使用缓存/内存来帮助处理此类问题?

我希望有人能用这些问题做点什么,加油!


共1个答案

匿名用户

如果不需要2048以上的精度,只使用半精度浮点数或其他数据类型有用吗?

单精度浮点数的除法/sqrt比双精度快,并且如果您的代码自动矢量化(例如在带有提前编译器的C中),则每个SIMD向量适合两倍的元素=每单位执行成本的工作量的两倍。

另外,与< code>double相比,一半的大小=一半的缓存占用空间,以及一半的缓存未命中时的内存带宽

实际的半精度浮点数(16 位)在 CPU 上没有太多硬件支持。英特尔芯片上的半精度浮点运算对于游戏中的很多东西来说可能太不准确了。

x86 div 指令只做整数除法。您谈论的是小数,但计算机本机处理整数和二进制分数(浮点数)。0.125 是 1 * 2^-3,所以它实际上是一个非常“简单”的浮点数(尾数 = 只是隐式 1)。

无论数据如何,大多数asm操作都是相同的速度,但division / sqrt是个例外。(浮点除法vs浮点乘法)。当然,除以0.125比乘以8要慢得多,所以还是这么做吧!例如,循环前的< code>mult = 1.0 /除数。如果您是用asm编写的,那么您甚至可以用< code>rcpps进行倒数,以获得比< code>divps更快的12位精度近似值。但实际上你不需要这么做。硬件浮点除法并不慢,尤其是当你要多次使用倒数的时候。

当然,Python 解释器的开销使其他一切相形见绌;例如,请参阅为什么按位运算符比乘法/除法/取模慢?

在使用 x87 FPU 而不是 SSE 标量浮点数的传统 32 位代码中(x86-64 将其用于普通标量 FP 数学),您可以设置 FPU 的内部舍入精度,这将在一定程度上加快 div/sqrt 的速度。将 FPU 切换为单精度。

(半相关:x87 FP堆栈是否仍然相关?)

最后,您是否有任何书籍推荐,有助于了解处理器如何进行操作并使用缓存/内存来帮助处理此类问题?

阅读Agner Fog的优化指南。他有C和asm优化指南,以及关于CPU内部工作的真正细节的微芯片指南,如果您是编译器开发人员或手动调整asm,您可以阅读这些指南。

另请参阅每个程序员都应该知道的内存?以提高缓存/内存性能。

通常,您可以通过将角度存储为[x, y]组件或[x, y, y]的单位向量来避免三角。这在游戏中被广泛使用,并允许您通过乘以旋转向量来旋转。

但是,当您确实需要像trig或log / exp这样的数学库函数时,您有时可以使用快速近似。通常,这仅在使用 SIMD 手动矢量化或使用汇编语言编写时才有意义。或者可能是纯粹的C / C,如果你可以让编译器不要把整数的事情弄得一团糟,变成FP位模式。在纯python中实现多步骤算法将比仅调用标准数学库函数慢。

    c语言三角函数的快速实现 < li >用C语言最快实现正弦、余弦和平方根运算(不需要非常精确) < li >如何在x64 CPU上快速计算正弦值? < Li > log 2(_ _ m256d)在AVX2中的高效实现 < li语言中非常快速的近似对数(自然对数)函数? < li >用SSE取对数,还是切换到FPU? < li >使用AVX最快实现指数函数

还有SSE和AVX的SIMD数学库,以及Clang的“_mm256_pow_ps”内在在哪里?对于SIMD数学库,您可以在其中找到各种函数的矢量化实现,其中一些具有不同的速度/精度权衡。

如果你用 asm 编写,x87 有像 fsin 这样的指令,但它们是用微码实现的,没有比你用单 uop “普通”指令更好的速度/精度权衡,例如使用 SSE2 标量数学。

在你担心用ASM写作之前,我建议优化SIMD一次做多个计算。(使用C和内在函数,或NumPy。)查看https://stackoverflow.com/tags/sse/info一些链接,尤其是这些幻灯片:失眠症游戏(GDC 2015)上的SIMD,了解更多关于如何选择数据布局的信息,以便SIMD可以为你工作。(避免使用一个SIMD向量来存储一个xy或xyz向量,相反,您需要4 x分量、4 y分量等的SIMD向量。)