C语言中int到float的强制类型转换

C语言|深入浅出讲解int转换为float全过程(附2017年统考大题案例) int转换为float类型为什么会发生精度损失? 精度损失的详细过程究竟是什么样的? 什么样情况float会发生精度损失?没有弄懂2017年浮点数统考大题? 这一篇用2017年统考大题案例帮你更深的理解浮点数的存储规则。 阅读详情
AI摘要

本文详细解析了C语言中32位int型数据强制转换为float型时精度损失的原因。通过深入探讨IEEE浮点数标准,解释了float型变量的内部表示方法及其与int型变量在位数上的差异。

最近在看一本名为的书。由于我所看过的计算机理论方面的书较少,加上自己大学期间一直也不用功,所以对于计算机的工作原理以及程序的工作方式我始终只知甚少,印象也十分模糊。

不过,应该说我碰到了一本好书。至少,通过昨晚对浮点数一章的阅读(呃...我的确之前对浮点数从没弄明白过),我终于了解了C语言中为什么32位int型数据强制转换到float型会出现精度不能完全保留的现象:

首先来看看我们可爱的int型变量吧,在一台典型的32位机器上一个有符号的int型的取值范围为-2147483648 ~ 2147483647(-2^31 ~ (2^31-1))(注1)。也就是说,在一个4字节(32位2进制),除去首位用于符号位表示正负外,其余的31位都是数字的有效位。

下面再来看看“万恶的”float型变量:根据IEEE的浮点标准,一个浮点数应该用下述形式来表示: 
V=(-1)^s * M * 2^E (公式1)
在C语言中,32位的float型变量有着这样的规定:首位表示符号位s,接下来的8位(指数域)用于表示2的指数E,剩余的23位(小数域)表示M(取值范围为[1,2)或[0,1))。除了上述规定以外,根据指数域的二进制表示情况不同,被编码的float型数字又可以分成三种情况——
1、规格化值。当指数域的8个二进制数字既非全零又非全1时,float数值就是这种情况。设指数域的八位二进制所表示的十进制数为e, 则公式1中的E就是 E = e - (2^7 - 1) (公式2);
而且此时,将小数域所表示的二进制假设为(f22)(f21)...(f1)(f0) (注2) ,则该小数域所表示的值即为f = 0.(f22)(f21)...(f1)(f0).于是M = 1 + f
2. 非规格化值。当指数域的8个二进制数字为全0时,float数值就为这种情况。这时指数域所表示的十进制数为0,规定指数值为 E = 1 - (2^7 - 1),也就是E为定值-126;此时小数域的值仍表示f = 0.(f22)(f21)...(f1)(f0),但是M的值却变成M = f。
3. 特殊值。当指数域的8个二进制数字为全1时即为这种情况。当小数域为全零时,该float值根据符号位的不同表示正无穷或者负无穷;当小数域为非全零时,该float值为NaN(Not a Number)。

以上,只是在C语言中对int和float的规约。具体在代码中执行强制类型转化究竟会发生什么?从下面两句很简单的语句开始:

 

int a = 3490593;
float b = (float)a;

 


那么在内存中a和b究竟存放的是什么值呢?

将a展开为二进制,其值为0000 0000 0011 0101 0100 0011 0010 0001,其十六进制即为0x00354321。 因为要转化为float型,所以首先要对上述二进制的表示形式改变为 M * 2^E 的形式.由于该数明显大于1,所以按照IEEE的标准,其浮点形势必然为规格化值。因此 ,转化后的形式为 
a = 1.101010100001100100001 * 2^21

根据 规格化值的定义,M = 1 + f. 所以f = 0.101010100001100100001.因为float型变量的小数域一共23位。所以b的最后23位可以得出,其值为10101010000110010000100

下面再演绎指数域的值:因为a的指数表示法中,指数E = 21。根据公式2,e = E + (2^7 -1) = 148.所以可以得出b的指数域的二进制表示为:10010100。在加上原数为正,所以符号位s=0。

所以,可以得出b的二进制表示为0 10010100 10101010000110010000100。转化为十六位进制则是0x4A550C84。换句话说,它存储在内存中的值是与a是完全不同的。但是其间还是有关联性的——a的首位为1的数值位后的二进制表示是与b的小数域完全相同的。

很快,问题就出现了。int型的有效位数是31,而float型小数域的有效位只有23位,也就是说如果上面的a的二进制的有效位超过了24位,那么float型的小数域的精度就不够了。因此必须进行舍入。比如:如果上面的a的二进制为0000 0001 1111 0101 0100 0011 0010 0001。这时b的小数域必须有24位才够,但是,这显然是不现实的,因此必须舍入到23位,舍入的原则是:所得结果的最低有效位为0。因此这个a在转换到float时,其精度就会丢失,因为该float的最后23位变成了11110101010000110010000——这显然是与原值不符的。

实际上,C语言中对于double型在32位机器上的小数域有52位,对于int型的31位有效位是绰绰有余了。这就是为什么大部分C语言教材上鼓励读者在执行强制类型转换时将int型转换成double。同时,这可能也是为什么int型能够直接隐式转换到double型的缘故。

注1:x ^ y表示 x的y次方
注2:(fn)取0或1

http://seapalace.blog.sohu.com/1586858.html

对文中关于e的描述不是很理解,如上文标红色部分。我按照上述描述可以做到整数2,3的手动转换到浮点数,就是不能对1做手动转换。后来又找到了维基上的描述:

http://zh.wikipedia.org/wiki/IEEE_754

贴出部分:

 

整体呈现[编辑]

IEEE 754浮点数的三个域

二进制浮点数是以符号数值表示法的格式存储——最高有效位被指定为符号位(sign bit);“指数部份”,即次高有效的e个比特,存储指数部分;最后剩下的f个低有效位的比特,存储“尾数”(significand)的小数部份(在非规约形式下整数部份默认为0,其他情况下一律默认为1)。

指数偏移值[编辑]

指数偏移值(exponent bias),是指浮点数表示法中的指数域的编码值为指数的实际值加上某个固定的值,IEEE 754标准规定该固定值为2e-1 - 1[2],其中的e为存储指数的比特的长度。

以单精度浮点数为例,它的指数域是8个比特,固定偏移值是28-1 - 1 = 128−1 = 127.单精度浮点数的指数部分实际取值是从128到-127。例如指数实际值为1710,在单精度浮点数中的指数域编码值为14410,即14410 = 1710 + 12710.

采用指数的实际值加上固定的偏移值的办法表示浮点数的指数,好处是可以用长度为e个比特的无符号整数来表示所有的指数取值,这使得两个浮点数的指数大小的比较更为容易。

规约形式的浮点数[编辑]

如果浮点数中指数部分的编码值在0 < exponent < 2e-1之间,且尾数部分最高有效位(即整数字)是1,那么这个浮点数将被称为规约形式的浮点数。

非规约形式的浮点数[编辑]

如果浮点数的指数部分的编码值是0,尾数为非零,那么这个浮点数将被称为非规约形式的浮点数。IEEE 754标准规定:非规约形式的浮点数的指数偏移值比规约形式的浮点数的指数偏移值大1.例如,最小的规约形式的单精度浮点数的指数部分编码值为1,指数的实际值为-126;而非规约的单精度浮点数的指数域编码值为0,对应的指数实际值也是-126而不是-127。实际上非规约形式的浮点数仍然是有效可以使用的,只是它们的绝对值已经小于所有的规约浮点数的绝对值;即所有的非规约浮点数比规约浮点数更接近0。规约浮点数的尾数大于等于1且小于2,而非规约浮点数的尾数小于1且大于0.

IEEE 754-1985标准采用非规约浮点数,源于70年代末IEEE浮点数标准化专业技术委员会酝酿浮点数二进制标准时,Intel公司对渐进式下溢出(gradual underflow)的力荐。当时十分流行的DEC VAX机的浮点数表示采用了突然式下溢出(abrupt underflow)。如果没有渐进式下溢出,那么0与绝对值最小的浮点数之间的距离(gap)将大于相邻的小浮点数之间的距离。例如单精度浮点数的绝对值最小的规约浮点数是1.0\times 2^{-126},它与绝对值次小的规约浮点数之间的距离为2^{-126}\times 2^{-23}=2^{-149}。如果不采用渐进式下溢出,那么绝对值最小的规约浮点数与0的距离是相邻的小浮点数之间距离的2^{23}倍!可以说是非常突然的下溢出到0。这种情况的一种糟糕后果是:两个不等的小浮点数X与Y相减,结果将是0.训练有素的数值分析人员可能会适应这种限制情况,但对于普通的程序员就很容易陷入错误了。采用了渐进式下溢出后将不会出现这种情况。例如对于单精度浮点数,指数部分实际最小值是(-126),对应的尾数部分从1.1111\ldots 11, 1.1111\ldots 10一直到0.0000\ldots 02, 0.0000\ldots 01,相邻两小浮点数之间的距离(gap)都是2^{-126}\times 2^{-23}=2^{-149};而与0最近的浮点数(即最小的非规约数)也是2^{-126}\times 2^{-23}=2^{-149}。

特殊值[编辑]

这里有三个特殊值需要指出:

  1. 如果指数是0并且尾数的小数部分是0,这个数±0(和符号位相关)
  2. 如果指数 = 2^{e} - 1并且尾数的小数部分是0,这个数是±∞(同样和符号位相关)
  3. 如果指数 = 2^{e} - 1并且尾数的小数部分非0,这个数表示为不是一个数(NaN)。

以上规则,总结如下:

形式指数小数部分
零00
非规约形式0非0
规约形式1到2^e-2任意
无穷2^e-10
NaN2^e-1非零

32位单精度[编辑]

单精度二进制小数,使用32个比特存储。

1823 位长
SExpFraction
3130至23
偏正值(实际的指数大小+127)
22至0 位编号(从右边开始为0)

S为符号位,Exp为指数字,Fraction为有效数字。 指数部分即使用所谓的偏正值形式表示,偏正值为实际的指数大小与一个固定值(32位的情况是127)的和。采用这种方式表示的目的是简化比较。因为,指数的值可能为正也可能为负,如果采用补码表示的话,全体符号位S和Exp自身的符号位将导致不能简单的进行大小比较。正因为如此,指数部分通常采用一个无符号的正数值存储。单精度的指数部分是−126~+127加上偏移值127,指数值的大小从1~254(0和255是特殊值)。浮点小数计算时,指数值减去偏正值将是实际的指数大小。

单精度浮点数各种极值情况:

类别正负号实际指数有偏移指数指数域尾数域数值
零0-12700000 0000000 0000 0000 0000 0000 00000.0
负零1-12700000 0000000 0000 0000 0000 0000 0000−0.0
1001270111 1111000 0000 0000 0000 0000 00001.0
-1101270111 1111000 0000 0000 0000 0000 0000−1.0
最小的非规约数*-12600000 0000000 0000 0000 0000 0000 0001±2−23 × 2−126 = ±2−149 ≈ ±1.4×10-45
中间大小的非规约数*-12600000 0000100 0000 0000 0000 0000 0000±2−1 × 2−126 = ±2−127 ≈ ±5.88×10-39
最大的非规约数*-12600000 0000111 1111 1111 1111 1111 1111±(1−2−23) × 2−126 ≈ ±1.18×10-38
最小的规约数*-12610000 0001000 0000 0000 0000 0000 0000±2−126 ≈ ±1.18×10-38
最大的规约数*1272541111 1110111 1111 1111 1111 1111 1111±(2−2−23) × 2127 ≈ ±3.4×1038
正无穷01282551111 1111000 0000 0000 0000 0000 0000+∞
负无穷11282551111 1111000 0000 0000 0000 0000 0000−∞
NaN*1282551111 1111non zeroNaN
* 符号位可以为0或1 .

64位双精度[编辑]


相关文章连接:

《C++类型转换方式总结 》http://www.cnblogs.com/ider/archive/2011/08/05/cpp_cast_operator_part6.html

《C++标准转换运算符dynamic_cast》http://www.cnblogs.com/ider/archive/2011/08/01/2123298.html

《C++标准转换运算符static_cast 》http://www.cnblogs.com/ider/archive/2011/07/31/2122385.html

《C++标准转换运算符reinterpret_cast》http://www.cnblogs.com/ider/archive/2011/07/30/2121953.html

C语言基础知识(二) 第二部分:类型转换 1、隐式类型转换(自动转换) 在有多种数据类型混合计算的时候,若未人为控制类型,系统会自动进行类型转换 转换的规则是:存储长度较短的转换成存储长度较长的,且不丢失数据 char--->short--->int--->unsigned int(--->long--->unsigned long)--->double float--------↑ 2、赋值转换 阅读详情

相关推荐

C++强制类型转换

如果读者,看过小林之前推送C语言的文章,会发现C++的强制类型转换和C语言一样,因为C++编写者将C语言的优点保留了下来,除此之外C++还特别增加了。在C++的表达式中,不同的数据类型会自动地转换类型进行运算,但有的时候也需要程序员自己进行强制类型转换,将某个表达式转换成自己所需要的数据类型。如果进行强制类型转换的对象是一个变量,则该变量的括号可以省略;在强制类型转换时,会得到一个中间变量,原来变量的类型未发生变化,但是如果从高精度向低精度转换时,会丢失精度。强制类型转换的一般形式为(类型名) (表达式).

weixin_54707168的博客 1663

C语言基础知识 - 笔记(一)

C语言基础知识 - 笔记(一) 数据类型 char—8位—127—255 int—16位—32767—65535 short—16位—32767—65535 long—32位—2147483647—4294967295 在表达式中,P是指针,*P是指向它的内容 函数指针 V.S. 指针函数 函数指针 int (*fun) ():本质上是一个指针,指向一个函数的地址,用于函数调用 指针函数

wangyu2010302660001的专栏 2277

C 语言类型转换

类型转换允许我们将一种数据类型转换为另一种数据类型。在C语言中,我们使用强制转换运算符进行类型转换,用(type)表示。注意:始终建议将较低的值转换为较高的值,以避免数据丢失。

Tom_Jerry__的博客 208

怎样在C语言中进行强制类型转换

1.强制类型转换的示例 (float) a; //将变量 a 转换为 float 类型 (int)(x+y); //把表达式 x+y 的结果转换为 int 整型 (float) 100; //将数值 100(默认为int类型)转换为 float 类型 2.代码举例 #include <stdio.h> int main() { float m=6.4; int n; n = (int)m; printf("%d",n); return 0; } //这里输出结果.

优快云_Marker的博客 9275

1.2 重叠因子:双重指数移动平均(Double Exponential Moving Average, DEMA)概念与Python实战

双重指数移动平均(Double Exponential Moving Average, DEMA)是一种改进的移动平均线指标,由Patrick Mulloy在1994年开发。相比传统的指数移动平均线(EMA),DEMA通过减少滞后性来提供更快的市场反应。它通过两次计算EMA并进行特殊组合来实现这一目标,可以在保持平滑性的同时减少滞后。

Kewin的博客 2168

基于FSL的DTI数据预处理流程

最近在学习处理DTI数据,总结了一份应用FSL做DTI数据预处理的流程与大家交流交流。如果有错误的地方欢迎大家指正!        我用的数据是Philips的数据,如果是GE或者西门子的数据可能会有所不同。   原始数据:包括3DT1数据和高分辨率DTI数据,均是dicom格式。 工具:MRICRON和FSL,所有的命令均在Linux的终端中运行。   1.格式转换:将后缀名为dcm

zaza_zaza的博客 2万+

c语言float转换为int_2.2 C++强制类型转换

点击上方“C语言入门到精通”,选择置顶第一时间关注程序猿身边的故事作者闫小林白天搬砖,晚上做梦。我有故事,你有酒么?强制类型转换运算符在C++的表达式中,不同的数据类型会自动地转换类型进行运算,但有的时候也需要程序员自己进行强制类型转换,将某个表达式转换成自己所需要的数据类型。强制类型转换的一般形式为(类型名) (表达式)如果进行强制类型转换的对象是一个变量,则该变量的括号可以省略;如果...

weixin_39900830的博客 1243

Figma入门-自动布局

Figma原型图制作内置组件友好,自动布局类似CSS flex,通过布局网格控制对齐、分布、换行等,前端熟悉的同学易上手,参数设置基本一致。

我码玄黄的博客 2174

C语言中int到float的强制类型转换(转)

在看csapp书时对于书上的一个32位机器上强制转换的例题苦思冥想不得解:x==(int)(float)x为什么是错的?x转换为float不应该是舔几个0么,再转换为Int又将小数点后的0去了么。知道看了这篇博文才知道一切都得从二进制的角度来看。 转:http://seapalace.blog.sohu.com/1586858.html 最近在看一本名为的书。由于我所看过的计算机理

格林先生的专栏 8816

process插件_利用SPSS 插件MLmed检验多水平中介的调节模型

本文介绍一个SPSS插件,用于检验多水平中介的调节,及该方法与Mplus的比较。1 Mlmed 简介及安装Mlmed 简介: Mlmed 由Rockwood 2017年开发,基于SPSS插件计算Multilevel moderated mediation. 可以提供multilevel mediation Monte Carlo 置信区间比如(模拟20000次),以及多水平调节的...

weixin_39976081的博客 5771

ANSYS Workbench对称分析进阶:手把手教你用Pre-Meshed Cyclic Region处理外部导入的复杂网格模型

本文详细介绍了ANSYS Workbench中Pre-Meshed Cyclic Region功能在处理外部导入复杂网格模型时的应用。通过循环对称分析技术,可显著减少计算资源消耗,特别适用于叶轮机械、齿轮组等周期性结构分析。文章深入解析了该功能的底层逻辑,并提供了从NASTRAN文件导入的离心压缩机叶轮案例,帮助工程师克服网格匹配难题。

weixin_28630185的博客 313

C语言强制类型转换

强制类型转换是通过类型转换运算来实现的。其一般形式为: (类型说明符) (表达式) 其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。例如: (float) a 把a转换为实型(int)(x+y) 把x+y的结果转换为整型在使用强制转换时应注意以下问题:1.类型说明符和表达式都必须加括号(单个变量...

hxh的博客 1万+

语言模型推理能力与计算表达力深度解析

语言模型的推理能力本质上是一种知识迁移与泛化应用的过程,其核心在于Transformer架构中的自注意力机制和前馈网络的协同作用。计算表达力作为衡量模型能力的关键指标,涉及函数逼近、组合泛化和上下文理解等多个维度。随着模型规模的扩大,涌现能力现象揭示了参数规模与推理能力之间的非线性关系。在实际应用中,通过提示工程和微调策略可以有效激活和优化模型的推理表现。当前研究正探索模块化架构和世界模型整合等方向,以突破长程推理和因果关系建模等前沿挑战。本文深入探讨了语言模型推理泛化的技术原理与实践方法,为理解计算表达力

weixin_42521032的博客 341

从double到float的强制类型转换

#include &amp;amp;amp;amp;amp;lt;stdio.h&amp;amp;amp;amp;amp;gt; union FLOATUN{ unsigned int a; float b; }; int main(){ FLOATUN fun; fun.b = 12.34; printf(&amp;amp;amp;amp;quot;c:%x\n&amp;amp;amp;amp;quot;,fun.a); doubl

qianshishangdi的博客 3万+

RK3399外设驱动之MIPI

RK3399外设驱动之MIPI 文章目录RK3399外设驱动之MIPIMIPI命令解析入口代码mipi显示配置实例rk3399mipi驱动rk mipi驱动注册过程rk32_mipi_dsi.c解析 内核版本 Linux4.4 平台 rk3399 作者 nineyole MIPI命令解析入口代码 MIPI的入口代码如下:kernel\drivers\video\rockchip\screen\lcd_mipi.c static int __init rk_mipi_screen_in

学无止境 2228

手把手教你学simulink(41.4)--逆变器电场景示例:基于Simulink的主从控制的多逆变器协同控制(Multi-Inverter Coordinated Control)

需求分析在现代电力系统中,分布式发电和储能系统的广泛应用使得多个逆变器并联运行成为常见的应用场景。为了确保多个逆变器之间的协同工作,实现系统的稳定性和高效性,通常采用主从控制(Master-Slave Control)策略。主从控制通过一个主控制器(Master)来协调多个从控制器(Slave),确保所有逆变器的输出电压、频率和功率分配符合预期目标。本项目将基于Simulink平台,开发一个多逆变器协同控制系统,采用主从控制策略,实现对多个逆变器的精确控制和优化。

MHD0815的博客 306

C语言指针强制类型转换

原文链接 概要: C语言中,任何一个变量都必须占有一个地址,而这个地址空间内的0-1代码就是这个变量的值。不同的数据类型占有的空间大小不一,但是他们都必须有个地址,而这个地址就是硬件访问的依据,而名字只是提供给程序员的一种记住这个地址的方便一点的方法。但是,不同的变量在机器中都是0-1代码,所以,我们不能简单的通过检查一个值的位来判断它的类型。 例如,定义如下: int a; float b; double c; long double d; (假设它们所占的字节分别是4、8、8、10,..

Find的博客 4821

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

C语言中的数据转换(自动类型转换与强制类型转换)

摘要:C语言数据类型转换分为自动(隐式)和强制(显式)两种。自动转换由编译器按优先级规则(如char→int→float→double)处理运算时的类型提升;强制转换通过(type)表达式实现,可能引发精度丢失或溢出。重点包括:1)int与short转换涉及截断或符号扩展;2)有符号/无符号整型转换需注意数值解析差异;3)float与int转换会丢失小数或精度。转换时需考虑取值范围,避免数据异常。

RZM666的博客 1167

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

c语言中的类型强制转换

强制类型转换是通过类型转换运算来实现的。其一般形式为: (类型说明符) (表达式) 其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。例如: (float) a 把a转换为实型(int)(x+y) 把x+y的结果转换为整型在使用强制转换时应注意以下问题:1.类型说明符和表达式都必须加...

chuanzou4767的博客 312

C语言·强制类型转换运算符

一般形式: (类型名)(表达式\常量\变量) (double)a 不管a原来是什么类型,此时临时将其强制变成double类型。 例: (int)(x+y)将x+y的值转换为整型 (float)(5%3)将5%3的值转换成单精度型2.0 注意: 1、优先级2级 2、(int)(x+y)与(int)x+y 【转换x加y的意思】意义不同 3、类型转换得一个中间值,原变量类型没有发生变化。 笔记于慕课...

3Y的太空充电站 8552

C语言基础——强制类型转换

强制类型装换: (数据类型)+变量 这里我用了time.h用于获取程序使用的时间 以下是代码: #include<stdio.h> #include<stdlib.h> #include<time.h> //强制类型装换: //(数据类型)+变量 //数据类型:int,float,char,double,unsigned,short,long //float->int int change1() { float num; printf("请输入一个浮点数(小

qq_51553982的博客 1252

C/C++中的类型转换

C/C++中的类型转换

2402_86735906的博客 273

C语言不同数据类型间的混合运算转换规则+常见数据类型

在程序中经常会遇到不同类型的数据进行运算,若一个运算符两侧的数据类型不同,则先自动进行类型转换,使两者具有同一类型,然后进行运算,现将规律总结如下: 1. +. -. *. /运算的两个数中有一个数为float或double型,结果是double型,因为系统将所有float型数据都先转换为double型,然后进行运算; 2. 若int型与float或double型数据进行运算,先将int型和f...

小武的博客 9856
上一篇: C++、C中有关double、float类型转换成int型,及取整,丢失精度问题。
下一篇: VC多线程编程
死神在世
博客等级 码龄14年 233粉丝 102原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值