想要改进这个问题?通过编辑这篇文章添加细节并澄清问题。
假设我们有一个实数a
,它具有无限精度。现在,我们在C/C中有浮动类型double
或flot
,并希望使用这些类型表示a
。假设“a_f”是a
的变量名称。
我已经理解了这些值是如何表示的,它由以下三部分组成:符号、分数和指数。根据使用的类型,分配给分数和指数的位数不同,这决定了“精度”。
在这个意义上,精度是如何定义的?
这是a
和之间绝对差异的上界a_f
(|a-a_f|),还是别的什么?
在double
的情况下,为什么“精度”以2^{-54}为界??
谢谢你。
浮点类型的精度通常定义为尾数中的位数,可以使用std::numeric_limits
尾数中的位数根据基数定义,使用std::numeric_limits
浮点类型的位数和基数都是实现定义的。我不知道任何实际实现支持2
以外的浮点基数(但C标准不需要)。
如果基数是2
std::numeric_limits
当将实值a
存储在浮点变量中时,存储的实际变量(您所描述的a_f
)是可以表示的最接近的近似值(假设不发生溢出等影响)。两者之间的差异(或差异的大小)不仅取决于尾数——它还取决于浮点指数——因此没有固定的上限。
实际上(用非常不准确的术语),一个值和它的浮点近似之间可能的差异与值的大小有关。浮点变量不代表最小和最大可表示值之间的一组均匀分布的值——这是使用尾数和指数表示的权衡,这是能够表示比相同大小的整数类型更大范围的值所必需的。
浮点数的问题是,它们越大或越小,就会变得越innacurate。例如:
double x1 = 10;
double x2 = 20;
std::cout << std::boolalpha << (x1 == x2);
正如预期的那样,打印false
。
但是,以下代码:
// the greatest number representable as double. #include <limits>
double x1 = std::numeric_limits<double>::max();
double x2 = x1 - 10;
std::cout << std::boolalpha << (x1 == x2);
出乎意料地打印出true
,因为数字太大以至于您无法真正表示x1-10
。它被四舍五入为x1
。
然后人们可能会问界限在哪里以及什么是界限。当我们看到不一致时,我们显然需要一些工具来检查它们。
std::
之后的下一个:
std::nextAfter
需要两个flot
或double
s。第一个参数是我们的起点,第二个参数代表我们想要计算下一个可表示值的方向。例如,我们可以看到:
double x1 = 10;
double x2 = std::nextafter(x1, std::numeric_limits<double>::max());
std::cout << std::setprecision(std::numeric_limits<double>::digits) << x2;
x2
略多于10
。另一方面:
double x1 = std::numeric_limits<double>::max();
double x2 = std::nextafter(x1, std::numeric_limits<double>::lowest());
std::cout << std::setprecision(std::numeric_limits<double>::digits)
<< x1 << '\n' << x2;
我机器上的输出:
1.79769313486231570814527423731704356798070567525845e+308
1.7976931348623155085612432838450624023434343715745934e+308
^ difference
这只是小数点后第16位。考虑到这个数字乘以10308,您可以看到为什么除以10
绝对没有改变。
很难谈论具体的值。人们可能会估计double
的精度为15位(点之前和之后的组合),这是一个不错的估计,但是,如果您想确定,请使用为该特定任务设计的方便工具。
例如,数字123456789
可以表示为.12*10^9
,也可以表示为.12345*10^9
或.1234567*10^9
。这些都不是精确的表示,有些比其他更好。你选择哪一个取决于你有多少位作为分数。更多的位意味着更高的精度。用于表示分数的位数称为“精度”。