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

2024-05-14 11:08

本文主要是介绍c++单精度和双精度的运算例子(计算机占位存储),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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

类型符号位指数位尾数位总位数(bit)
float182332
double1115264

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

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

 

1.4的不同存储符号位指数位尾数位16进制表示
float0011111110110 0110 0110 0110 0110 0113FB33333
double0011111111110110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 01103FF6666666666666


 

在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位有效数字,所以第一行打印的结果都一样。

上面的验证结果如图:

这篇关于c++单精度和双精度的运算例子(计算机占位存储)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/988580

相关文章

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元

Python获取C++中返回的char*字段的两种思路

《Python获取C++中返回的char*字段的两种思路》有时候需要获取C++函数中返回来的不定长的char*字符串,本文小编为大家找到了两种解决问题的思路,感兴趣的小伙伴可以跟随小编一起学习一下... 有时候需要获取C++函数中返回来的不定长的char*字符串,目前我找到两种解决问题的思路,具体实现如下:

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(