c - 将浮点数分解为整数部分和小数部分
问题描述
我正在实现分数延迟线算法。涉及的任务之一是将浮点值分解为其整数部分和小数部分。我知道在 SO 上有很多关于这个主题的帖子,我可能读过其中的大部分。但是,我还没有找到一篇涉及此场景细节的帖子。
该算法必须使用 64 位浮点值。
输入浮点值保证始终为正。(延迟时间不能为负)
输出整数部分必须由整数数据类型表示。
整数数据类型必须有足够多的位,这样才能进行双整数转换而没有溢出的风险。
必须避免因浮点值缺乏精确的内部表示而导致的问题。(即 9223372036854775809.0 可能在内部表示为 9223372036854775808.9999998,当转换为整数时,它错误地变为 9223372036854775808)
无论舍入模式或编译器优化设置如何,该实现都应该工作。
所以我写了一个函数:
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) 最有效的实现来将浮点数分解为其整数和小数部分,同时考虑上面提到的点列表。
解决方案
阅读下面的评论后更新答案。
如果您已经确定值在 [0, 2^63-1] 范围内,那么简单的强制转换会比这个函数更快,llround()
因为这个函数也可以检查溢出(在我的系统上,手册页说明了,但是 C 标准确实如此不需要)。
例如,在我的机器上(x86-64 Nehalem),强制转换是一条指令(cvttsd2si
),llround()
显然不止一条。
我能保证通过简单的强制转换(截断)得到正确的结果,还是舍入更安全?
取决于您对“正确”的含义。如果 中的值double
可以用 正确表示int64_t
,那么您肯定会得到完全相同的值。但是,如果该值不能精确地表示,double
则在强制转换时会自动执行截断。如果您想以不同的方式对值进行舍入,那就另当别论了,您必须使用ceil()
,floor()
或中的一个round()
。
如果您还确定没有值将是 +/- Infinity 或 NaN(在这种情况下您可以使用-Ofast
),那么如果您想要截断,那么您的第二个实现应该是最快的,而如果您想要第三个实现应该是最快的floor()
价值。
推荐阅读
- reactjs - React 中的事件驱动方法?
- php - WooCommerce 中特定购物车小计的免费赠品产品
- javascript - 如何使用 javascript 编写解析器?
- php - PHP 调用可调用变量:\App\$variable\etc
- aws-lambda - 无服务器 API 网关 Lambda 中的 CORS 策略阻止的资源,即使它已设置
- python - boto3.Session().client 和 boto3.client 有什么区别?
- flutter - 无法调用 initState 和更新 (riverpod state_notifier)
- python - 使用布隆过滤器会比在 Python 中搜索字典或列表更快吗?
- django - 如何使用 django 模板限制 html 中的数据?
- nginx - 两个位置在 nginx 中无法用于 MERN 应用程序