试图验证(使用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值?
答案 0 :(得分:5)
浮点数不会将数据存储在基数10中,而是将它存储在基数2中。因此,4611690000000000000
实际上并不是一个非常圆的数字。它的二进制表示是:
100000000000000000000111001111100001000001110001010000000000000.
正如您所看到的,这需要大量数据才能准确记录。但是,实际打印的数字具有以下二进制表示形式:
11111111111111111111111111111111111111111111111111111111111100
正如你所看到的那样,这是一个更加圆润的数字,并且从2的幂中减去4的事实可能是由于转换为base-10算法的四舍五入。
作为不能正确适合浮动的数字的示例,请尝试您期望的数字:
4611690000000000000
你会发现情况会有很大不同。
答案 1 :(得分:4)
浮动保留了如此多的信息,因为你正在使用一个非常接近2的幂的数字。
浮点格式以基本二进制科学记数法存储数字。在您的情况下,它存储为类似
的内容1.0000000 ... [61 zeroes] ... 00000001 * 2 ^ 62。
浮动格式不能存储62个小数位,所以最后1个会被截断...但是我们留下了2 ^ 62,这几乎完全等于你的数字#3;重新尝试存储。
我在制造示例方面表现不佳,但CERT不是;您可以查看错误的号码转化here会发生什么情况的示例。请注意,该示例使用的是Java,但C ++使用相同的浮点类型;另外,第一个例子是4字节int
和4字节float
之间的转换,但这进一步证明了你的观点(需要存储的整数信息少于在你的例子中,它仍然失败了。)