Jer*_*wen 20 c floating-point double bit-manipulation micro-optimization
我希望采用IEEE双精度并以最有效的方式删除它的任何整数部分.
我想要
1035 ->0
1045.23->0.23
253e-23=253e-23
Run Code Online (Sandbox Code Playgroud)
我不关心正确处理非正规,无穷大或NaN.我不介意有点麻烦,因为我知道我正在使用IEEE双打,所以它应该适用于各种机器.
无分支代码将是更优选的.
我的第一个念头是(伪代码)
char exp=d.exponent;
(set the last bit of the exponent to 1)
d<<=exp*(exp>0);
(& mask the last 52 bits of d)
(shift d left until the last bit of the exponent is zero, decrementing exp each time)
d.exponent=exp;
Run Code Online (Sandbox Code Playgroud)
但问题是我想不出一个有效的方法来向左移动指数的最后一位为零,如果没有设置所有最后一位,它似乎需要输出零.这似乎与基数2对数问题有关.
对此算法或任何更好的算法的帮助将非常感激.
我应该注意到我想要无分支代码的原因是因为我希望它能有效地进行矢量化.
Mar*_*iot 35
简单的事情怎么样?
double fraction = whole - ((long)whole);
Run Code Online (Sandbox Code Playgroud)
这只是从值本身中减去double的整数部分,余数应该是小数部分.当然,这可能会有一些代表性问题.
Ste*_*non 12
最佳实现完全取决于目标体系结构.
在最近的英特尔处理器,这可以用两个指令来实现:roundsd
和subsd
,但不能表达便携 C代码.
在某些处理器上,最快的方法是对浮点表示进行整数运算.早期的Atom和许多ARM CPU都会浮现在脑海中.
在其他一些处理器上,最快的事情是转换为整数并返回,然后减去,分支以保护大值.
如果您要处理大量值,可以将舍入模式设置为舍入为零,然后将+/- 2 ^ 52加减并减去截断为整数的数,然后从原始值中减去以获得分数.如果你没有SSE4.1,但确实有一个现代化的英特尔CPU并想要进行矢量化,这通常是你能做到的最好的.但是,只有处理多个值才有意义,因为更改舍入模式有点贵.
在其他架构上,其他实现是最佳的.一般来说,谈论C程序的"效率"是没有意义的; 仅针对特定体系结构的特定实现的效率.
Meh*_*dad 10
#include <math.h>
double fraction = fmod(d, 1.0);
Run Code Online (Sandbox Code Playgroud)
该函数remainder
计算余数,但不计算整数部分modf
:
#include <math.h>
double fracpart(double input)
{
return remainder(input, 1.);
}
Run Code Online (Sandbox Code Playgroud)
这是最有效的(和便携式)的方式,因为它没有计算不必要的值来完成这项工作(参见modf
,(long)
,fmod
,等)
正如Mattew在评论中所建议的那样,我写了一些基准代码来将此解决方案与本页提供的所有其他解决方案进行比较.
请在下面找到65536次计算的时间测量值(使用关闭优化的Clang编译):
method 1 took 0.002389 seconds (using remainder)
method 2 took 0.000193 seconds (casting to long)
method 3 took 0.000209 seconds (using floor)
method 4 took 0.000257 seconds (using modf)
method 5 took 0.010178 seconds (using fmod)
Run Code Online (Sandbox Code Playgroud)
再次与Clang,这次使用-O3
标志:
method 1 took 0.002222 seconds (using remainder)
method 2 took 0.000000 seconds (casting to long)
method 3 took 0.000000 seconds (using floor)
method 4 took 0.000223 seconds (using modf)
method 5 took 0.010131 seconds (using fmod)
Run Code Online (Sandbox Code Playgroud)
原来最简单的解决方案似乎给大多数平台上的最好成绩,具体方法来执行该任务(fmod
,modf
,remainder
)实际上是超级慢!