我从Computer Representation of Floating Point Numbers学到了计算机的浮点表示法。
根据教程,对于32位浮点数,最小的正归一化
可存储的数字为2 ^(-126),最大归一化的数字为(2-2 ^(-23))* 2 ^(127)≈2 ^(128)。但是,精度受到23位有效数字的限制。
我认为32位浮点数可以表示2 ^ 60而没有任何错误,因为:
使用指数和有效位数的隐藏位(1)表示2 ^ 60就足够了。
我的测试代码如下(VS2013 + win10):
#include <iostream>
#include <math.h>
#include <bitset>
using namespace std;
int main()
{
union
{
float input; // assumes sizeof(float) == sizeof(int)
int output;
} data;
data.input = pow(2., 60.);
std::bitset<sizeof(float) * CHAR_BIT> bits(data.output);
std::cout << "Total: " << bits << std::endl;
cout << "Sign: " << bits[31] << endl << "Exponent: ";
for (int i = 30; i > 22; i--)
{
cout << bits[i];
}
cout << endl << "Significand: ";
for (int i = 22; i >= 0; i--)
{
cout << bits[i];
}
cout << endl;
cout.precision(20);
cout << data.input << endl;
printf("%f", data.input);
}
然后我得到输出:
Total: 01011101100000000000000000000000
Sign: 0
Exponent: 10111011
Significand: 00000000000000000000000
1152921504606847000
1152921504606847000.000000
我打印二进制表示形式,这是正确的。但令我感到困惑的是,为什么最后三位数字为零。正确的输出应为1152921504606846976。
此外,我将代码更改如下:
#include <iostream>
#include <math.h>
#include <bitset>
using namespace std;
int main()
{
for (int i = 1; i < 65; i++)
{
union
{
float input; // assumes sizeof(float) == sizeof(int)
int output;
} data;
data.input = pow(2, i);
std::bitset<sizeof(float) * CHAR_BIT> bits(data.output);
cout.precision(20);
cout << i << ": " << data.input << endl;
//printf("%f\n", data.input);
}
}
输出为:
1: 2
2 : 4
3 : 8
......
55 : 36028797018963968
56 : 72057594037927936
57 : 144115188075855870
58 : 288230376151711740
59 : 576460752303423490
60 : 1152921504606847000
61 : 2305843009213694000
62 : 4611686018427387900
63 : 9223372036854775800
64 : 18446744073709552000
从2 ^ 57开始出现零。谁能告诉我为什么会这样吗?
答案 0 :(得分:4)
这不是float
正确表示2 60 的失败。 Microsoft的软件无法正确地将2 60 转换为十进制(即,失败是在格式代码中,而不是在float
算术中,尽管Microsoft的pow
之前的实现也不准确)。无论所涉及的实际值是多少,您所使用的软件仅产生17位十进制数字。使用Apple LLVM 10.0.0(clang-1000.11.45.5)编译的同一程序会产生:
55: 36028797018963968 56: 72057594037927936 57: 144115188075855872 58: 288230376151711744 59: 576460752303423488 60: 1152921504606846976 61: 2305843009213693952 62: 4611686018427387904 63: 9223372036854775808 64: 18446744073709551616
C标准允许微软的行为,但是从数学上来说当然不是很好。