为了获得速度,为了获得速度,将双精度转换为整数

时间:2010-05-12 16:58:48

标签: c casting integer double printf

<\ n>在Redis(http://code.google.com/p/redis)中有与元素相关联的分数,以便对这些元素进行排序。即使许多用户实际按整数排序(例如unix次),这个分数也是双倍的。

保存数据库时,我们需要编写这个双打ok磁盘。这是目前使用的:

  snprintf((char*)buf+1,sizeof(buf)-1,"%.17g",val);

此外,还会检查无穷大和非数字条件,以便在最终数据库文件中表示这一点。

不幸的是,将double转换为字符串表示非常慢。虽然我们在Redis中有一个函数,它以更快的方式将整数转换为字符串表示形式。所以我的想法是检查是否可以将double转换为整数而不丢失数据,然后使用该函数将整数转换为字符串(如果这是真的。)

为了提供良好的加速,当然整数“等价”的测试必须快。所以我使用的技巧可能是未定义的行为,但在实践中效果很好。这样的事情:

double x = ... some value ...
if (x == (double)((long long)x))
    use_the_fast_integer_function((long long)x);
else
    use_the_slow_snprintf(x);

在我的推理中,上面的双重转换将double转换为long,然后转换为整数。如果范围适合,并且没有小数部分,则该数字将在转换后继续存在,并且与初始数字完全相同。

由于我想确保这不会破坏某些系统中的内容,我加入了freenode上的#c并且我受到了很多侮辱;)所以我现在正在这里尝试。

有没有一种标准方法可以在不超出ANSI C的情况下做我想做的事情?否则,上面的代码是否适用于当前Redis目标的所有Posix系统?那就是现在运行Linux / Mac OS X / * BSD / Solaris的拱门?

为了使代码更健全,我可以添加的是在尝试演员之前对double的范围进行明确检查。

感谢您的帮助。

4 个答案:

答案 0 :(得分:6)

也许一些旧时尚定点数学可以帮助你。如果您将double转换为固定点值,您仍然可以获得小数精度,并且转换为字符串就像添加单个shift函数的int一样简单。

另一个想法是推出自己的snprintf()函数。许多FPU单元本身支持从double到int的转换,因此应该是快速的。将其转换为字符串也很简单。

为您提供一些随机的想法。

答案 1 :(得分:2)

这样做的问题是比较不会按照你期望的方式运作。仅仅因为一个浮点值小于另一个浮点值并不意味着它作为整数的表示将小于另一个浮点数。另外,我看到你比较其中一个(前)双重值是否相等。由于低位中的舍入和表示错误,您几乎从不想要这样做。

如果你只是在寻找某种键来执行像哈希这样的操作,那么它可能会很好。如果您真正关心哪些值确实具有更大或更小的价值,那么这是一个坏主意。

答案 2 :(得分:1)

只要x在长长的范围内,我就没有看到强制转换的问题。也许你应该看看modf()函数,它将double分成它的积分和小数部分。然后,您可以针对(double)LLONG_MIN和(double)LLONG_MAX添加检查以确保整体部件。虽然双精度可能有困难。

但在做任何事情之前,你是否确定它通过衡量其性能确实是一个瓶颈?并且整数值的百分比是否足够高以至于它真的会有所不同?

答案 3 :(得分:0)

你的测试完全正常(假设你已经分别处理了无穷大和NAN) - 当你真的想要比较浮点数是否相等时,它可能是极少数的一个。它不会调用未定义的行为 - 即使x超出long long的范围,您也只会得到“实现定义的结果”,这里没问题。

唯一的 美中不足的是,负零将以正零结束(因为负零比较等于正零)。