我正在编写一段代码,其中我需要处理不一定在0到1范围内的uvs (2D纹理坐标)。举个例子,有时我会得到一个u分量为1.2的uv。为了处理这个问题,我实现了一个包装,它通过执行以下操作来导致平铺:
u -= floor(u)
v -= floor(v)这样做会导致1.2变成0.2,这是预期的结果。它还处理负的情况,例如-0.4变为0.6。
然而,这些对floor的调用相当慢。我已经使用英特尔VTune评测了我的应用程序,并且我花费了大量的周期来进行这种现场操作。
在对这个问题做了一些背景阅读后,我想出了以下函数,它的速度更快,但仍然有很多需要改进的地方(我仍然会招致类型转换惩罚,等等)。
int inline fasterfloor( const float x ) { return x > 0 ? (int) x : (int) x - 1; }我见过一些使用内联汇编完成的技巧,但似乎没有一个是完全正确的,或者有任何显着的速度提高。
有没有人知道处理这种情况的诀窍?
发布于 2010-03-01 05:34:18
所以你想要一个非常快的float->int转换?AFAIK >float转换很快,但至少在MSVC++上,float->int转换会调用一个小的辅助函数ftol(),该函数会做一些复杂的工作来确保完成符合标准的转换。如果您不需要这样严格的转换,那么可以进行一些汇编黑客操作,假设您使用的是x86兼容的CPU。
下面是一个使用MSVC++内联汇编语法的快速浮点数到整型数向下舍入的函数(不管怎样,它应该会给你正确的想法):
inline int ftoi_fast(float f)
{
int i;
__asm
{
fld f
fistp i
}
return i;
}在64位MSVC++上,您需要一个外部.asm文件,因为64位编译器拒绝内联汇编。该函数基本上使用原始的x87浮点数指令来加载浮点数(fld),然后将浮点数存储为整数( FPU )。(警告:您可以通过直接调整CPU上的寄存器来更改此处使用的舍入模式,但不要这么做,否则会破坏很多东西,包括MSVC的sin和cos实现!)
如果您可以假设在CPU上支持SSE (或者有一种简单的方法来创建支持SSE的代码路径),您也可以尝试:
#include <emmintrin.h>
inline int ftoi_sse1(float f)
{
return _mm_cvtt_ss2si(_mm_load_ss(&f)); // SSE1 instructions for float->int
}...which基本上是一样的(加载浮点数,然后存储为整数),但使用的是SSE指令,它的速度要快一点。
其中之一应该涵盖昂贵的浮点数到整型的情况,并且任何整型到浮点型的转换都应该是很便宜的。很抱歉在这里专门针对微软,但这就是我做过类似性能工作的地方,我通过这种方式获得了很大的收益。如果可移植性/其他编译器是一个问题,那么您将不得不考虑其他问题,但是这些函数可能编译为两条指令,占用的时间小于5个时钟,而不是使用100+时钟的辅助函数。
发布于 2017-01-10 11:17:46
老问题,但我遇到了它,它让我有点抽筋,因为它没有得到令人满意的回答。
TL;DR:*不要**使用内联汇编、内部函数或任何其他给定的解决方案!相反,使用快速/不安全的数学优化进行编译(g++中的“-ffast- math -funsafe-math-optimizations -fno-math-errno”)。floor()如此慢的原因是因为如果强制转换溢出,它会改变全局状态(FLT_MAX不适合任何大小的标量整数类型),这也使得向量化变得不可能,除非您禁用严格的IEEE-754兼容性,您可能无论如何都不应该依赖它。使用这些标志进行编译会禁用问题行为。
以下是一些备注:
带有标量寄存器的
发布于 2010-03-01 05:23:21
您需要的操作可以使用fmod函数来表示(fmodf用于浮点数,而不是双精度数):
#include <math.h>
u = fmodf(u, 1.0f);你的编译器很有可能会以最有效的方式来做这件事。
或者,您对最后一位的精度有多关心?你能给你的负值设定一个下限吗,比如知道它们永远不会低于-16.0的东西?如果是这样的话,像这样的东西将为你节省一个条件,如果它不是可以用你的数据可靠地分支预测的东西,那么它很可能是有用的:
u = (u + 16.0); // Does not affect fractional part aside from roundoff errors.
u -= (int)u; // Recovers fractional part if positive.(在这个问题上,取决于你的数据看起来是什么样子,以及你使用的处理器,如果它们中的很大一部分是负的,但很小的一部分低于16.0,你可能会发现在执行条件整数转换之前添加16.0f会给你带来加速,因为它使你的条件是可预测的。或者,您的编译器可能正在使用条件分支以外的其他方法来执行此操作,在这种情况下,它没有什么用处;如果不测试和查看生成的程序集,就很难说。)
https://stackoverflow.com/questions/2352303
复制相似问题