c++单精度和双精度的运算例子(计算机占位存储)

计算机中float, double类型数据分别占据4,8个字节,其中float类型和double可以表示的小数位数不同,导致了精度不同。double的精度更高。

计算机中数据的表示由:符号位, 指数位,尾数位组成。比如一个float类型数字的二进制由左到右依次是符号位,指数位,尾数位。

类型 符号位 指数位 尾数位 总位数(bit)
float 1 8 23 32
double 1 11 52 64

数字1.4在计算机中的存储转换如下:

先将整数和小数都变二进制表示:1.0110 0110 0110 0110 0110 011,然后整数部分不需要右移,所以float的指数位=2*7-1+0=127;double的指数位=2*10-1+0=1023。各个部分的二进制表示如下。

 

1.4的不同存储 符号位 指数位 尾数位 16进制表示
float 0 01111111 0110 0110 0110 0110 0110 011 3FB33333
double 0 01111111111 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 3FF6666666666666


 

在c++单精度和双精度的运算结合如下两个test示例理解如下:

#include <iostream>

float f1 =1.4;
float f2 = 5.0;
float f3 = 7.0;
int i = 7;
using namespace std;

void test1()
{
	printf("test %f %f %f\n", f1 * f2, f1 * 5.0, f3 / f1);
    cout << (f1 * f2 == i) << '\t' << (f1 * f2 == f3) << endl;
    cout << (f1 * 5.0f == f3) << '\t' << (f1 * f2 == f1 * 5.0f) << endl;
    cout << (f3 / f1 == 5.0) << '\t' << (f3 / f1 == f2);
}

void test2()
{
	printf("test %f %f %f\n", f1 * f2, f1 * 5.0, f3 / f1);
    cout << (f1 * f2 == i) << '\t' << (f1 * f2 == f3) << endl;
    cout << (f1 * 5.0 == f3) << '\t' << (f1 * f2 == f1 * 5.0) << endl;
    cout << (f3 / f1 == 5.0) << '\t' << (f3 / f1 == f2);
}
int main(void)
{
	cout<<"test1"<<endl;
	test1();
	cout<<endl<<"test2"<<endl;
	test2();
	
	cout<<endl<<endl<<"验证输出"<<endl;
	double f11=1.4;
	cout<<"sizeof(5.0)="<<sizeof(5.0)<<", sizeof(f1*f2)=" <<sizeof(f1*f2)<<", sizeof(f3/f1)=" <<sizeof(f3/f1)<<endl;
	cout.precision(20);
	cout<<"1.4的单精度 f1="<<f1<<endl<<"1.4的双精度 f11="<<f11<<endl;
	cout<<"双精度转单精度 double2float: "<<float(f11)<<endl;
	cout<<"单精度转双精度 float2double: "<<double(f1)<<endl;

    cout<<"单精度*单精度 f1*5.0f="<<f1*5.0f<<", 单精度*双精度 f1*5.0="<<f1*5.0<<", 双精度*双精度 f11*5.0="<<f11*5.0<<endl;
    cout<<"当单精度*单精度结果有小数时候:"<<endl; 
    cout<<"单精度*单精度 f1*6.0f="<<f1*6.0f<<", 单精度*双精度 f1*6.0="<<f1*6.0<<", 双精度*双精度 f11*6.0="<<f11*6.0<<endl;
    
    cout<<endl<<"i.和j. 的验证:"<<endl;
    cout<<"f3/f2==1.4 =>"<< (f3/f2==1.4)<<",  f3/f2==f1 =>"<<(f3/f2==f1)<<endl;
    
    cout<<endl<<"d.的假设验证:"<<endl;
    cout<<"float(f1*5.0)==i =>"<<(float(f1*5.0)==i)<<endl;
    f1=0.125;
    cout<<"f1 * 56.0 == i =>"<< (f1 * 56.0 == i)<<endl;
	return 0;


}

test1和test2的两段代码涉及的是float类型和double类型数据在计算机中的存储问题。

用到的基础知识:

1, C++中默认5.0是一个double类型,5.0f表示指定这是一个float类型的数字。

2, 精度(float*double)=> double*double=精度(double), 精度(float*float)=精度(float), 精度(double*double)=精度(double)

3,  float类型用4个字节表示,double类型用8个字节表示,double可以用更多的位表示小数点部分(这部分知识可以参考数字在计算机中的表示,https://blog.csdn.net/ultrakang/article/details/39322275),所以有小数的情况下,double比float精度更高。而float转double精度不变,double转float精度降低。

4,float和double转换中精度降低的情况只作用在存在小数位情况。且只存在于小数位的非0尾数大于23bit情况下(因为float尾数是23个bit, double尾数是52个bit)。

再来看本例中给定的数据 f1=1.4; f2=5.0; f3=7.0; i=7。共进行了如下的运算结果比对,跟着对应的结果分析。

a.  f1 * f2 == i       =》1,左边 f1*f2 等效于 float*float,结果仍然是float,恰好是整数,所以f1 * f2 == i 成立。

b.  f1 * f2 == f3     =》1,左边 同 a. ,右边f3是float类型,不涉及数据类型转换,精度不变,所以f1 * f2 == f3 成立。

c.  f1 * 5.0f == i    =》1,左边 f1*5.0f 等效于float*float,其它同a. ,所以f1 * 5.0f == i  成立 。

d.  f1 * 5.0 == i    =》0,左边 f1*5.0等效于double*double, f1=1.4,1.4作为float和double两种类型在计算机存储的精度是不同的,并且结果也是double类型,精度更高,所以f1 * 5.0 == i 不成立,如果将f1*5.0转换成float类型则成立,即:float(f1*5.0)==i 成立。或者将本例中f1=1.4换成f1=0.125(即一个小数点位数可在23bit之内表示的数 , 则f1 * 56.0 == i 成立,因为0.125值的float和double类型在计算机存储中是一样的。

e.  f1 * f2 == f1 * 5.0f   =》1,右边f1 * 5.0f是float*float,不涉及类型转换问题,同b. 所以f1 * f2 == f1 * 5.0f 成立。

f.   f1 * f2 == f1 * 5.0   =》0,右边同d. 1.4在计算机中作为float和double表示的精度不同,f1*5.0是double*double=double,比f1*f2的float*float=float精度更高,所以f1 * f2 == f1 * 5.0不成立。

g.  f3 / f1 == 5.0     =》1,  左边float/foat=float,结果用float类型表示,小数位尾数为0,右边double类型的5.0的小数位尾数也都是0,所以f3 / f1 == 5.0 成立。可以结合下面的 i. 来理解。

h.  f3 / f1 == f2      =》1, 左边和右边都是float类型,精度不变,所以 f3 / f1 == f2成立。可以结合下面的j. 来理解。

补充:

i.  f3 / f2 == 1.4   =》0, 左边结果float类型,右边1.4是double类型,精度不同,所以f3 / f2 == 1.4不成立。

j. f3 / f2 == f1   =》1,右边类型是float,1.4用float表示,不涉及精度降低问题,所以f3 / f2 == f1 成立。

cout默认打印出7位有效数字,所以第一行打印的结果都一样。

上面的验证结果如图:

猜你喜欢

转载自blog.csdn.net/u010420283/article/details/113812979