【发布时间】: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