【问题标题】:Rounding to use for int -> float -> int round trip conversion用于 int -> float -> int 往返转换的舍入
【发布时间】:2009-12-10 19:29:38
【问题描述】:

我正在为数据库引擎编写一组数值类型转换函数,我担心将大整数浮点值转换为精度更高的整数类型的行为。

以将 32 位 int 转换为 32 位单精度浮点数为例。浮点数的 23 位有效数产生大约 7 位十进制数字的精度,因此转换任何超过 7 位数字的 int 将导致精度损失(这是正常的和预期的)。但是,当您将这样的浮点数转换回整数时,您最终会在低位数字中得到其二进制表示的伪影:

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    int a = 2147483000;
    cout << a << endl;
    float f = (float)a;
    cout << setprecision(10) << f << endl;
    int b = (int)f;
    cout << b << endl;

    return 0;
}

打印出来:

2147483000
2147483008
2147483008

结尾的 008 超出了浮点数的精度,因此似乎不希望将其保留在 int 中,因为在数据库应用程序中,用户主要关心十进制表示,而结尾的 0 用于表示无意义的数字。

所以我的问题是:是否有任何众所周知的现有系统可以在 float -> int(或 double -> long long)转换中执行十进制有效数字舍入,是否有任何众所周知的有效算法可以这样做?

(注意:我知道有些系统有十进制浮点类型,比如IEEE 754-2008定义的那些。但是,它们没有主流硬件支持,也没有内置到C/C++中。我可能想在以后支持它们,但我仍然需要直观地处理二进制浮点数。)

【问题讨论】:

  • 这种情况会发出一个危险信号,询问“为什么会有往返转换?”这意味着该值应作为整数而不是浮点数存储在数据库中。有点像简化代数表达式。
  • 好问题。我当然不打算进行往返转换,并且数据库引擎本身不会导致这种情况发生。然而,这个数据库是为密集的内存数据设计的,所以我需要使用尽可能小的类型。我不希望用户(他们可以提交自己的类似 SQL 的查询)认为他们在将二进制浮点数转换为更高精度的 int 或十进制浮点数时获得的精度比实际高得多。
  • 在使用数据库时,应谨慎选择数据库和代码中的类型。大多数时候,你知道你是否想要小数。如果您不想要小数,请使用整数或长整数。如果你想要十进制,那么你想使用双精度(除非你真的确定你需要非常有限的精度,否则很少使用浮点数)。 如果 C++ 类型与数据库类型不匹配,我建议不要进行特殊情况转换,而是引发错误。

标签: c++ c floating-point rounding


【解决方案1】:

std::numeric_limits&lt;float&gt;::digits10 说你只能得到 6 位精确的浮点数。

为您的语言、处理器和数据分配到calculate-the-decimal-length-of-an-integer(或here)选择一个有效的算法。然后减去digits10 所说的精确位数,以获得要剔除的位数。使用它作为索引来查找 10 的幂以用作模数。等等。

一个问题:假设您将浮点数转换为小数并执行这种舍入或截断。然后将该“调整后的”小数转换为浮点数,然后使用相同的舍入/截断方案转换回小数。你得到相同的十进制值吗?希望是的。

这不是您真正想要的,但可能会很有趣:A Proposal to add a max significant decimal digits value to the C++ Standard Library Numeric limits

【讨论】:

  • 谢谢!我忽略了 numeric_limits 中digits10 的存在,并为此目的引入了我自己的特征模板(基于有效位中的位)。您的方法基本上是我决定采用的方法,因此最好进行一些独立验证。这个提议确实很有趣;它为这些问题提供了更多视角。
【解决方案2】:

如果您将 2147483008 写入二进制 (1111111111111111111110110000000) 或十六进制 (0b0x7FFFFD80),则自然会出现尾随零。最“正确”的做法是跟踪任何这些形式的无关紧要的数字。

或者,您可以将 int 中前七个有效数字之后的所有数字从浮点数转换为整数后将其归零(最好通过舍入),因为浮点数包含大约七个有效数字。

【讨论】:

  • 优秀的澄清点。但是,我真的不希望使用二进制或十六进制来显示存储在此数据库中的数据。我的问题真的归结为实施第二段的智慧/先例和最有效的方法。
猜你喜欢
  • 2019-06-24
  • 1970-01-01
  • 2021-10-12
  • 2016-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-04
  • 2011-09-28
相关资源
最近更新 更多