int与float深入理解

2023-11-08

别在int与float上栽跟头


        int与float是我们每天编程都用的两种类型,但是我们真的足够了解它们吗。昨天在博客园看到一个比较老的笑话: “昨天晚上下班回家,一民警迎面巡逻而来。突然对我大喊:站住!民警:int 类型占几个字节?  我:4 个。  民警:你可以走了。  我:为什么问这样的问题? 民警:深夜还在街上走,寒酸苦逼的样子,不是小偷就是程序员。”(注:看到有朋友评论说占几个字节跟具体的环境有关,学过C++的都知道,在C++这样的语言中确实取决于环境,但是在Java跟C#中不管什么环境都规定是4个字节,所以后边我们只讨论4个字节的情况)

        看完这个笑话,我脑袋立马将float、double等类型的字节长度闪了个遍。我知道float也占4个字节,但存储结构跟int是不一样的,并且表示范围也不一样。紧接着就出现了一个疑问,到底哪些int值是float不能表示的呢?如果你回答不了这个问题,那还是好好地了解一下吧,如果我说的不够清楚,请多查点其他的资料看一下。

       为什么有些int是float表示不了的呢?因为int与float同样占4个字节,float表示的范围又比int大并且还包含很多小数,那int的每个值都能被float表示就是不可能的事情了。在平时的编程中好像也没有感觉什么不对呀,这是为什么呢?先把这个问题留到后边,原理说清楚了再来回答这个问题。在文章的下边帖了一个进制转换程序,方便大家使用。


小数十进制与二进制的转换

        二进制转换成十进制:跟整数转换一个原理,例如二进制11.11转换为十进制 1*2^1+1*2^0+1*2^(-1)+1*2^(-2)=3.75。

        十进制转换成二进制:整数部分不用说了,跟整数的十进制转成二进制没有区别。小数部分采用乘2取整的方式,比如3.75整数部分对应的二进制是11。小数部分0.75,先乘以2等于1.5,取1.5的整数部分1。再用0.5(上次乘2的结果的小数部分)乘以2等于1.0,取1.0的整数部分1,现在已经没有小数部分了,终止。0.75对应的二进制就是.11。

        所以3.75对应的二进制是11.11。注意这里的3.75和1.11只是浮点数十进制与二进制的不同表示形式,存储结构是一样的,因为本来就是同一个数。内存结构又是怎么样的呢,下边介绍。   二. float的存储结构   float也是占32位,第一位是符号位(sign),符号位后边8位是指数(exponent),最后23位是尾数(mantissa)。

        float值的二进制表示形式是:sign* mantissa* 2^exponent。注意这个表达式是对应上述存储结构的二进制。

        符号位,表述浮点数的正或者负,0代表正,1代表负。


        指数位,实际也是有正负的,但是没有单独的符号位,在计算机的世界里,进位都是二进制的,指数表示的也是2的N次幂,8位指数表达的范围是0到255,而对应的实际的指数是-127到128。也就是说实际的指数等于指数位表示的数值减127。这里特殊说明,-127和+128这两个指数数值在IEEE当中是保留的用作多种用途的,这里就不多做介绍了,有兴趣的可以查阅其他资料。

        尾数位,只代表了二进制的小数点后的部分,小数点前的那位被省略了,当指数位全部为0时省略的是0否则省略的是1,为什么呢,看个例子:

        二进制11.11表示成指数形式是1.111*2^1,0.1111表示成指数形式是1.111*2^(-1)。由此可见,正常情况下二进制的指数形式是肯定有一个1的,所以存储的时候直接省略。但是在指数位全部为0时,指数是-127,这个数字是有特殊含义的,在尾数全部为0时代表的数值是0,省略的那位是0,如果省略的是1那么0这个数字就没法用float表示了。


结合例子理解一下

        那我们就看一下3.75的内存结构到底是什么样子的。首先转化成二进制形式11.11。转化成二进制指数形式1.111*21。由此我们可以得知尾数部分是111(将1省略掉了),不足23位的后边补0,指数部分是1+127=128,对应二进制10000000。所以存储结构就是01000000011100000000000000000000。

        反过来转换一下,比如某个float的存储结构是01000000011100000000000000000000,符号位是正的,指数位是128,实际的指数是128-127=1,尾数是111,再加上省略的那位就是1.111。所以对应的二进制指数形式是1.111*2^1,对应的二进制是11.11,对应的十进制是3.75。


        到这里我们就可以看出,实际上尾数决定了浮点数的精度,尾数只有23位,加上省略的那位就是24位。如果一个int类型的值小于224,那么float是完全可以表示的。如果int类型大于224就不一定能表示了。假如一个int数值的二进制表示形式是100000000000000000000000,表示成指数形式是1.00000000000000000000000*2^23,对应的float的类型,尾数位全部为0,指数位是23+127=150,这样完全没有问题。假如一个int数值的二进制表示形式是1000000000000000000000001,表示成指数形式是1.000000000000000000000001*2^24,对应的float的类型尾数位是000000000000000000000001一共24位,这样就完全超出了float最多容纳23位尾数的能力。所以就不能正确表达这个int值了。由此也可以得出不能被float准确表达的最小int值是2^24+1。我们再将1000000000000000000000001的值加1,变成了1000000000000000000000010,这样变换为指数形式可以看出尾数又变为了23位,也就是说25位的二进制整数最后一位是0才能被float准确表示,每2个数就有一个不能被准确表示。如果是26位的二进制整数最后两位都是0才可以被float准确表达,每4个数就有3个不能被准确表示,以此类推。


        现在再来回答为什么在编程的过程中似乎没怎么引起注意,这是因为,我们平时用的数值基本都小于224+1=16777217。


原文链接:别在int与float上栽跟头



java中的float和double的精度问题


1、背景知识 
在java中没有细讲,只是讲了float占32位(bit),double占 64位。 
对于计算机来说,用位数表示是合适的。但有人喜欢用字节(byte)表示。一个字节占8位。 
1 byte = 8 bit. 
所以float占4个字节,double占8个字节。 
不过我还是喜欢用位数表示。这样更直接,也更容易理解计算机是怎么存储这些类型的。 

对于精度和范围,还是参考一下c++吧。 



2、存储知识 
计算器存储浮点数的方法:(用科学计数法存储) 
将要存的数先转换为小数(0.xxxxxx)x10的n次幂的形式进行存储。 
例如: 
3.1415 将被转换为:0.31415 x 10^1 
100000 将被转换为:0.1 x 10^6 

首先申明一点,先范围(有效数字位,包括整数位和小数位),再精度。 



3、下面切入正题 
===================== 
在c++中单精度float类型与双精度double类型的问题 

【"单精度用float表示,在计算机中使用4位字节(32位bit)来表示,具有7位有效数字"】 

float类型存储的时候1个bit是符号位,8个bit是指数位,剩下的23个bit是有效数字位。 
2的23次方是8388608,即7位有效数字,精度(10进制)。 

一个单精度的浮点数在内存当中占用了32个bit位,按照浮点数的表示标准,最高位表示符号,这32位一部分用来表示阶码,一部分用来表示小数部分。 
按照这个表示方法转化成10进制之后,它能表示的最高精度是7位有效数字。 

比如 
float a=3.14159;a在内存中实际上表示为0.314159乘以10的1次方(0是符号位),而分配给a的存储单元就分为两部分,一部分存0.314159,一部分存指数1,而且也都是转化为2进制来存。 

================== 
float ,1位符号位, 8位指数位,23位尾数位 
double,1位符号位,11位指数位,52位尾数位 

float尾数位23位,2^23=8.3E6,7位,所以不同的编译器规定不同,有些是7位,有些8位 
double尾数52位,2^52=4.5E15,15位,所以double的有效位数是15位 


后记: 
数一下有效数字位数(整数位+小数位),7位以内的用float,15位以内的用double 
但是还有一点小小的区别: 
float f =  (float) 62345678.912345;  // => 6.234568E7  共 7 位 
float f2 =  (float) 12345678.912345; // => 1.2345679E7 共 8 位 

(精度问题,float精度为7--8位,8位的情况是第一位是1,当是2时进位后面的精度丢失?)

原文链接:java中的float和double的精度问题



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

int与float深入理解 的相关文章

随机推荐

  • 直流电机驱动PWM频率(转)

    源 直流电机驱动PWM频率 1 没有统一的标准 其实PWM的频率和你的电机感抗和你需要的速度响应时间有很大的关系 一般的电机用14K就足够了 当然自需要简单的调速可以随便选 如果电机转速比较高 感抗比较小 可以使用比较高的频率 一般最好不要
  • 【详细】使用MkDocs搭建个人博客网站

    使用MkDocs搭建个人博客网站 0 安装python3 7 注意 可以在个人用户下安装 不要覆盖系统原有python 下载Python依赖环境 yum install gcc patch libffi devel python devel
  • 并发编程(线程)面试题总结2022

    目录 并发编程三要素是什么 在 Java 程序中怎么保证 多线程 的运行安全 什么是多线程 多线程的优劣 形成死锁的四个必要条件是什么 创建线程有哪几种方式 继承 Thread 类 实现 Runnable 接口 实现 Callable 接口
  • ubuntu12.10 32位系统使用framebuffer显示24深度bmp文件

    参考了网上很多例子 但是大多数都是有问题 只能显示部分 而且图片不是很清楚 在csdn上下载了一个代码是ok的 总结一下就是 1 mmap的大小如何确定 2 bmp文件的保存顺序是由下到上层的 3 fread char pix 1 size
  • Pandas: 使用read_excel、describe、loc方法求极差、变异系数与四分位数间距

    极差 最大值 最小值 变异系数 标准差 平均数 四分位间距 QU上四分位 QL下四分位 coding utf 8 import pandas as pd init data data init data summary xls data p
  • ICTCLAS2013 Java版本的使用方法

    这个工具是什么 先看看他的官方介绍吧 NLPIR汉语分词系统 又名ICTCLAS2013 主要功能包括中文分词 词性标注 命名实体识别 用户词典功能 支持GBK编码 UTF8编码 BIG5编码 新增微博分词 新词发现与关键词提取 张华平博士
  • PNP结算方法(后面可能有空再补充了)

    一些pnp的实验结论 1 yaw角稳定性上 在opencv中 SOLVEPNP UPNP SOLVEPNP EPNP SOLVEPNP DLS gt gt SOLVEPNP IPPE gt SOLVEPNP AP3P gt SOLVEPNP
  • 10 行代码,实现手写数字识别

    识别手写的阿拉伯数字 对于人类来说十分简单 但是对于程序来说还是有些复杂的 不过随着机器学习技术的普及 使用10几行代码 实现一个能够识别手写数字的程序 并不是一件难事 这是因为有太多的机器学习模型可以拿来直接用 比如tensorflow
  • react 项目中使用js-export-excel导出excel

    第一步 首先添加包 npm npm install js export excel yarn yarn add js export excel 第二步 组件引入 import ExportJsonExcel from js export e
  • 嵌入式FreeRTOS学习三,FreeRTOS任务的挂起和恢复

    二 任务的挂起和恢复 有时候我们需要暂停某个任务的运行 过一段时间以后在重新运行 这个时候要是使用任务删除和重建的方法的话 那么任务中变量保存的值肯定丢失了 FreeRTOS给我们提供了解决这种问题的方法 那就是任务挂起和恢复 当某个任务要
  • k8s通过Kuboard安装Metrics server报错的解决办法

    文章目录 通过Kuboard安装Metrics server 确认 metrics server 是否正常运行 确认 ApiService 是否正常 排查步骤1 根据ApiService的日志 查443端口 排查步骤2 metrics se
  • 该微信用户未开启“公众号安全助手”的消息接收功能,请先开启后再绑定

    1 关注微信公众号 公众平台安全助手 2 关闭该公众号的消息免打扰 如下 1 点击3个点 2 点击设置 3 关闭消息免打扰 如图所示 置灰
  • k8s之Deployment与service

    一 概念 pod 最小执行调度单元 Deployment 部署无状态应用 Daemonset 部署守护应用 Cronjob 部署定时任务 job 部署定时任务 statefulset 部署有状态应用 service endpoint ing
  • iOS上传App Store报错:this action cannot be completed -22421 解决方案

    iOS上传App Store报错 this action cannot be completed 22421 解决方案 参考文章 1 iOS上传App Store报错 this action cannot be completed 2242
  • 牛客 · 奇♂妙拆分

    奇 妙拆分 题目描述 在遥远的米 奇 妙 妙 屋里住着一群自然数 他们没事就喜欢拆 开自己来探 究 现在他们想知道自己最多能被拆分成多少个不同的自然数 使得这些自然数相乘的值等于被拆分的数 输入描述 第 1 1 1行输入一个整数 T
  • 一图看懂架构划分原则:技术划分 OR 领域划分?

    架构划分原则 技术划分 描述 按技术用途组织系统组件 典型示例 分层 多层 架构 组件按技术层组织 用户界面 与用户直接交互的部分 业务规则和核心处理 逻辑和算法 与数据库交互 数据存取和查询 数据库层 数据存储和管理 优点 当大部分更改与
  • Linux域名解析得到ip地址

    Linux下域名解析得到ip地址代码如下 include
  • Redis(持续完善....)

    1 Redis结构 Redis是一款基于内存的NoSQL数据存储服务 是非关系型的 是使用K V结构进行存储的 gt lt 基于内存 读写数据均在内存中直接操作 gt
  • 高性能Mysql——SQL执行计划分析(EXPLAIN)

    文章目录 通过EXPLAIN进行执行计划分析 ID select type Table Partitions Type Extra possible keys Key key len Ref Rows Filtered EXPLAIN不能完
  • int与float深入理解

    别在int与float上栽跟头 int与float是我们每天编程都用的两种类型 但是我们真的足够了解它们吗 昨天在博客园看到一个比较老的笑话 昨天晚上下班回家 一民警迎面巡逻而来 突然对我大喊 站住 民警 int 类型占几个字节 我 4 个