为了(使用VS2012)验证一本书的主张(第二句),
When we assign an integral value to an object of floating-point type, the fractional part is zero.
Precision may be lost if the integer has more bits than the floating-point object can accommodate.
我写了以下小程序:
#include <iostream>
#include <iomanip>
using std::cout;
using std::setprecision;
int main()
{
long long i = 4611686018427387905; // 2^62 + 2^0
float f = i;
std::streamsize prec = cout.precision();
cout << i << " " << setprecision(20) << f << setprecision(prec) << std::endl;
return 0;
}
输出为
4611686018427387905 4611686018427387900
我期望表单的输出
4611686018427387905 4611690000000000000
一个4字节的浮点型如何能够保留这么多关于8字节整数的信息?是否有i的值可以实际证明这一主张?
发布于 2017-01-04 10:41:25
浮点数不会将数据存储在基数10中,而是存储在基数2中。因此,4611690000000000000
实际上不是一个非常舍入的数字。它的二进制表示是:
100000000000000000000111001111100001000001110001010000000000000.
正如您所看到的,这将需要大量数据才能准确记录。然而,实际打印的数字具有以下二进制表示形式:
11111111111111111111111111111111111111111111111111111111111100
正如您所看到的,这是一个非常四舍五入的数字,事实是它从2的幂中减去了4,这很可能是由于转换为基数10的算法中的舍入。
作为一个无法正确放入浮点数的数字的示例,请尝试您期望的数字:
4611690000000000000
你会注意到,这将是非常不同的结果。
发布于 2017-01-04 10:42:06
浮点数保留了如此多的信息,因为您正在处理的数字非常接近2的幂。
float格式以基本的二进制科学记数法存储数字。在您的例子中,它被存储为类似于
1.0000000...61个零...00000001* 2^62。
float格式不能存储62位小数,因此最后的1被截断...但是我们还剩下2^62,这几乎完全等于您试图存储的数字。
我不擅长制造示例,但CERT并非如此;您可以查看一个错误的数字转换here的示例。注意,示例是用Java语言编写的,但是C++使用相同的浮点类型;另外,第一个示例是4字节int
和4字节float
之间的转换,但这进一步证明了您的观点(需要存储的整数信息比示例中的少,但仍然失败)。
https://stackoverflow.com/questions/41455327
复制相似问题