设计一种方法测试float类型能保留的小数位数长度

RT
2025-04-23 20:23:36
推荐回答(2个)
回答1:

如果你单单想测试一下一个浮点数(十进制)最多能保存多少位小数而没有数据丢失的话,以下一段代码就可以了:
#include
#include
int main(int argc, int *argv[]){
union{
float f;
unsigned int ui;
}fi, fi1;
fi.ui = 0x00800000;//2的-126次方
printf("%.150f\n", fi.f);

fi1.ui = 0x7e800000;//2的126次方
printf("%.150f\n", fi.f * fi1.f);
printFloat(fi.f * fi1.f);

system("pause");
return 0;
}
输出为:
0.000000000000000000000000000000000000011754943508222875000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
解释一下,单精度浮点数的存储格式为(IEEE 754标准)(从高位到低位):
数符1位,阶码8位,尾数23位
共32位,阶码用移码,尾数用原码,采用隐藏位技术。
最小的单精度正数为2的-126次方(阶码1,尾数0。正负浮点数的表示范围对称,所以按最小正数计算)。相应的二进制表示为:
0,0000 0001,23个0
转换为十六进制就是上面代码中出现的0x00800000。
第一个输出结果去掉末尾的0只有54位小数,但是2的-126次方等于0.5的126次方,应有126位小数才对。那么这就是printf的问题了,它无法继续输出剩余的位。虽然printf无法继续输出,但是fi.f表示的实际精度是没有丢失的,为了证明这一点,后面 fi.f * fi1.f结果为1。这些都能从fi.f在内存中的存储看出来。
回到你的问题,答案就是126位了。其实第一次回答给出的是54,那是被printf骗了,后来想想0.5的126次方小数位数为126。
(顺便说句,虽然最长126位这样的小数float能无损表示,并不是说任何小于126位的小数都能精确表示,具体参考组成原理喽)
下面附上一段代码,用来查看一个单精度浮点数在内存中的表示:
#include
#include
void printUnsigned(unsigned int num){
unsigned int i = 0x80000000;
while(i != 0){
printf("%d ",(i & num) > 0?1:0);
i >>= 1;
}
printf("\n");
}

void printFloat(float num){
union{
float f;
unsigned int ui;
}fi={num};

printUnsigned(fi.ui);
}
希望采纳!如有问题欢迎继续交流。

回答2:

#include
#include
#include
int main()
{

float fl=1.0/3.0;
int floatDigit; //float型小数精度位数
char digit[30],* pStr;
pStr=gcvt(fl,30,digit); //转换有一定误差
floatDigit=strlen(pStr)-2;
//std::cout<printf("%.25f%c%d\n",fl,':',floatDigit);
return 0;
}

输出结果:
0.3333333432674408000000000:16
请按任意键继续. . .