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++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

MyBatis-plus处理存储json数据过程

《MyBatis-plus处理存储json数据过程》文章介绍MyBatis-Plus3.4.21处理对象与集合的差异:对象可用内置Handler配合autoResultMap,集合需自定义处理器继承F... 目录1、如果是对象2、如果需要转换的是List集合总结对象和集合分两种情况处理,目前我用的MP的版本

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

使用SpringBoot+InfluxDB实现高效数据存储与查询

《使用SpringBoot+InfluxDB实现高效数据存储与查询》InfluxDB是一个开源的时间序列数据库,特别适合处理带有时间戳的监控数据、指标数据等,下面详细介绍如何在SpringBoot项目... 目录1、项目介绍2、 InfluxDB 介绍3、Spring Boot 配置 InfluxDB4、I

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

python中update()函数的用法和一些例子

《python中update()函数的用法和一些例子》update()方法是字典对象的方法,用于将一个字典中的键值对更新到另一个字典中,:本文主要介绍python中update()函数的用法和一些... 目录前言用法注意事项示例示例 1: 使用另一个字典来更新示例 2: 使用可迭代对象来更新示例 3: 使用

python连接sqlite3简单用法完整例子

《python连接sqlite3简单用法完整例子》SQLite3是一个内置的Python模块,可以通过Python的标准库轻松地使用,无需进行额外安装和配置,:本文主要介绍python连接sqli... 目录1. 连接到数据库2. 创建游标对象3. 创建表4. 插入数据5. 查询数据6. 更新数据7. 删除

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c