首页 > 解决方案 > 将浮点数分解为整数部分和小数部分

问题描述

我正在实现分数延迟线算法。涉及的任务之一是将浮点值分解为其整数部分和小数部分。我知道在 SO 上有很多关于这个主题的帖子,我可能读过其中的大部分。但是,我还没有找到一篇涉及此场景细节的帖子。

所以我写了一个函数:

 double my_modf(double x, int64_t *intPartOut);

如您所见,它的签名类似于 C 标准库中的 modf() 函数。

我想出的第一个实现是:

double my_modf(double x, int64_t *intPartOut)
{
    double y;
    double fracPart = modf(x, &y);
    *intPartOut = (int64_t)y;
    return fracPart;
}

我也一直在试验这种实现——至少在我的机器上——比以前的运行速度更快,但是我怀疑它的稳健性。

double my_modf(double x, int64_t *intPartOut)
{
    int64_t y = (int64_t)x;
    *intPartOut = y;
    return x - y;
}

...这是我最近的尝试:

double my_modf(double x, int64_t *intPartOut)
{
    *intPartOut = llround(x);
    return x - floor(x);
}

我无法决定哪种实现最适合使用,或者是否还有其他我认为可以更好地实现以下目标的实现。我正在寻找 (1) 最强大和 (2) 最有效的实现来将浮点数分解为其整数和小数部分,同时考虑上面提到的点列表。

标签: ccastingfloating-pointintegerprecision

解决方案


阅读下面的评论后更新答案。

如果您已经确定值在 [0, 2^63-1] 范围内,那么简单的强制转换会比这个函数更快,llround()因为这个函数也可以检查溢出(在我的系统上,手册页说明了,但是 C 标准确实如此不需要)。

例如,在我的机器上(x86-64 Nehalem),强制转换是一条指令(cvttsd2si),llround()显然不止一条。

我能保证通过简单的强制转换(截断)得到正确的结果,还是舍入更安全?

取决于您对“正确”的含义。如果 中的值double可以用 正确表示int64_t,那么您肯定会得到完全相同的值。但是,如果该值不能精确地表示,double则在强制转换时会自动执行截断。如果您想以不同的方式对值进行舍入,那就另当别论了,您必须使用ceil(),floor()或中的一个round()

如果您还确定没有值将是 +/- Infinity 或 NaN(在这种情况下您可以使用-Ofast),那么如果您想要截断,那么您的第二个实现应该是最快的,而如果您想要第三个实现应该是最快的floor()价值。


推荐阅读