我正在寻找一种以快速便携(IEEE 754)方式将float
截断为int
的方法。原因是因为在这个函数中,50%的时间都花在了演员身上:
float fm_sinf(float x) {
const float a = 0.00735246819687011731341356165096815f;
const float b = -0.16528911397014738207016302002888890f;
const float c = 0.99969198629596757779830113868360584f;
float r, x2;
int k;
/* bring x in range */
k = (int) (F_1_PI * x + copysignf(0.5f, x)); /* <-- 50% of time is spent in cast */
x -= k * F_PI;
/* if x is in an odd pi count we must flip */
r = 1 - 2 * (k & 1); /* trick for r = (k % 2) == 0 ? 1 : -1; */
x2 = x * x;
return r * x*(c + x2*(b + a*x2));
}
答案 0 :(得分:4)
在x86上使用x87 FPU指令时,主要发生float-&gt; int强制转换的缓慢。要进行截断,需要将FPU控制字中的舍入模式更改为舍入为零并返回,这往往非常慢。
使用SSE而不是x87指令时,可以在没有控制字更改的情况下进行截断。您可以使用编译器选项(如GCC中的-mfpmath=sse -msse -msse2
)或将代码编译为64位来执行此操作。
SSE3指令集具有FISTTP
指令,可在不更改控制字的情况下转换为带截断的整数。如果指示假设SSE3,编译器可以生成该指令。
或者,C99 lrint()
函数将使用当前舍入模式转换为整数(除非您更改它,否则为round-to-nearest)。如果您删除copysignf
字词,则可以使用此选项。不幸的是,这种功能在十多年后仍然无处不在。
答案 1 :(得分:2)
要便携,你必须添加一些指令并学习几种汇编语言,但理论上你可以使用一些内联汇编将浮点寄存器的部分移动到eax / rax ebx / rbx并转换你需要的东西手,浮点规格虽然是一个痛苦的屁股,但我很确定如果你用汇编你会更快,因为你的需求是非常具体的,系统方法可能更通用,效率更低目的
答案 2 :(得分:1)
我找到了Sree Kotay的fast truncate method,它提供了我所需的优化。
答案 3 :(得分:0)
您可以使用frexpf来获取尾数和指数,并在适当的位位置检查原始尾数(使用int
),从而完全跳过转换为union
(已计算使用指数)来确定(象限依赖)r
。