在我正在分析的应用程序中,我发现在某些情况下,此功能可以占用总执行时间的10%。
正在使用MSVC ++ 2008编译器供参考......我不记得modf是否映射到单个指令,或者是否有可能使其更快。
另见here关于sqrt函数的类似问题
与sqrt不同,我真的不知道modf是如何工作的。有装配操作吗?例如,你可以这样做:
modf(float input,int &intPart, float &floatPart)
{
intPart= (int)input;
floatPart= input - intPart;
}
但我认为这会导致施法/转换等处罚,快速实施如何运作?
答案 0 :(得分:2)
你在这里得到了很好的答案,但其他90%的时间去了哪里?
请勿查看每个例程的独占时间。
查看每行代码的包含%时间,如果可能,请将其包括阻塞时间,而不仅仅是CPU时间。
这样,你可能会发现那部分时间,甚至不需要 modf 函数或其他函数。
获取该信息的简便方法是this technique。
补充:当您发现可以执行的优化时,预计总执行时间会减少,但不要指望百分比必然会下降。如果你摆脱其他东西,你在 modf 和/或 sqrt 中的%时间实际上可能会上升,或者如果你发现你可以记住它们,它们可能会失效(和因此,例如,将它们称为“更少”。
在这种优化方法中,您可以将程序的执行历史视为一个大调用树,您正在寻找的是可以修剪的整个分支。更重要的是,由于一行代码可以出现在调用树的多个分支中,因此将其修剪成一个修剪它。
答案 1 :(得分:2)
modf
的良好实现可以非常快(在当前硬件上大约10个周期)。糟糕的实现可能非常慢(大约100个周期)。一个非常糟糕的实现可能会花费1000个周期。我不知道微软的实现状态是什么,但是你可能会看到各种开源C库中有很多很好的实现。
您提议的实施需要一些捷径,不符合C标准;特别是,在input
太大而无法成功转换为整数的情况下,它会行为异常严重。在某些情况下,它也会出现零错误的迹象,但您可能并不关心这一点。
另请注意,您可以使用支持C99标准的编译器/ C库,因为您可以利用modff
函数并避免转换为双精度和从双精度转换的开销。我知道英特尔的数学库(随编译器一起提供)具有出色的modf
和modff
实现。 GCC还支持C99单精度变体。
FWIW,我对您提出的实现进行了基准测试,并且(假设编译器代码优秀),它比英特尔库modff
快约50%(但英特尔的实现,为所有输入提供了正确的结果)。我进行基准测试的最快正确实现仅比实现慢15%(但同样,为所有输入提供了正确的结果,甚至可以正确设置浮点状态标志以启动)。
答案 2 :(得分:1)
modf 应该确实是一个非常快速的函数,所以问题可能是它仍然是一个函数(即,没有内联)。您可以尝试使用与库中完全相同的代码,但在头中使用内联静态函数,以允许编译器内联它。
当函数内联时,如果你总是只使用其中一个尾数/指数,那么编译器应该足够聪明,只能发出代码来计算那个部分,从而进一步加快速度。
如果您仍然有兴趣自己动手,请查看wikipedia on the floating point format
答案 3 :(得分:0)
请注意,库必须尽可能快地解决所有极端情况 - 对于类似的情况,这会增加相当多的复杂性。
如果您的演员版本适用于您的程序,这意味着您没有任何超出int范围的浮动,并且您已经确认它对于负数或者您是正确的不关心他们,那么它可能会更快一点。
答案 4 :(得分:0)
我还看到过在DLL中调用小例程的情况(就像CRT的情况一样)在进出DLL时会受到胶水代码的影响。在这种情况下,即使实现本身是相同的,滚动自己并改变它的编译方式(例如,内联它)也可以提高性能。 YMMV,POITROAE等
答案 5 :(得分:0)
您的实现可能是x86上最快的实现。但请记住,您将支持的输入范围限制在int
!
您可能希望将编译器设置为使用SSE(2)进行浮点数学运算,因为这样可以消除(可能很慢)控制字更改以进行截断。