C51浮点数显示、浮点数表示方法

C51浮点数显示、浮点数表示方法C51中的浮点数存储方式–n年前曾在c51bbs论坛中发布过Float浮点形,它是符合IEEE-754标准的单精度浮点形数据,在十进制中具有7位有效数字。FLOAT型据占用四个字节(32位二进制数),在内存中的存放格式如下:字节地址(由低到高)0123浮点数内容MMMMMMMMMMMMMMMMEMMMMMMMSEEEEEEE其中,S为符号位,存放在最高字节

大家好,又见面了,我是你们的朋友全栈君。

C51中的浮点数存储方式
–n年前曾在c51bbs论坛中发布过

Float 浮点形,它是符合IEEE-754标准的单精度浮点形数据,在十进制中具有7位有效数字。FLOAT型据占用四个字节(32位二进制数),在内存中的存放格式如下:
字节地址(由低到高)0 1 2 3
浮点数内容 MMMMMMMM MMMMMMMM E MMMMMMM S EEEEEEE
其中,S为符号位,存放在最高字节的最高位。“1”表示负,“0”表示正。E为阶码,占用8位二进制数,存放在高两个字节中。注意,阶码E值是以2为底的指数再加上偏移量127,这样处理的目的是为了避免出现负的阶码值,而指数是可正可负的。阶码E的正常取值范围是1~254,从而实际指数的取值范围为-126-127。M为尾数的小数部分,用23位二进制数表示,存放在低三个字节中。尾数的整数部分永远为1,因此不予保存,但它是隐含的。小数点位于隐含的整数位“1”的后面。

例如浮点数124.75 = 42F98000H 在内存中的存放格式为:
字节地址 +0 +1 +2 +3
浮点数内容 00000000 10000000 1 1111001 0 1000010

124.75D=1111100.11B=1.11110011*2E6
阶码=6D+127D=133D=10000101B
符号位=0

参考示例程序一:
typedef union{

float flt;
unsigned char fltc[4];
} Float;

main()
{

Float a;
unsigned char i;
a.flt=124.75;
for(i = 0; i < 4; i++)
printf(“%x\t”,a.fltc[i]);
printf(“\n”);
}

参考示例程序二:
main()
{

float a;
unsigned char i;
unsigned char *j;
a=124.75;
j = (unsigned char *)&a;
for(i = 0; i < 4; i++)
printf(“%x\t”,j[i]);
printf(“\n”);
}

 

C51里用4字节存储一个浮点数,格式遵循IEEE-754标准(详见c51.pdf第179页说明)。一 
个浮点数用两个部分表示,尾数和2的幂,尾数代表浮点上的实际二进制数,2的幂代表指 
数,指数的保存形式是一个0到255的8位值,指数的实际值是保存值(0到255)减去127,一个 
范围在-127到+128之间的值,尾数是一个24位值(代表大约7个十进制数),最高位MSB通常是 
1,因此不保存。一个符号位表示浮点数是正或负。 
浮点数保存的字节格式如下: 
地址        +0          +1           +2           +3 
内容    SEEE EEEE   EMMM MMMM    MMMM MMMM    MMMM MMMM 
这里 
S 代表符号位,1是负,0是正 
E 偏移127的幂,二进制阶码=(EEEEEEEE)-127。 
M 24位的尾数保存在23位中,只存储23位,最高位固定为1。此方法用最较少的位数实现了 
较高的有效位数,提高了精度。 
零是一个特定值,幂是0 尾数也是0。 
浮点数-12.5作为一个十六进制数0xC1480000保存在存储区中,这个值如下: 
地址 +0     +1     +2     +3 
内容0xC1   0x48   0x00   0x00 
浮点数和十六进制等效保存值之间的转换相当简单。下面的例子说明上面的值-12.5如何转 
换。 
浮点保存值不是一个直接的格式,要转换为一个浮点数,位必须按上面的浮点数保存格式表 
所列的那样分开,例如: 
地址       +0           +1            +2            +3 
格式   SEEE EEEE    EMMM MMMM     MMMM MMMM     MMMM MMMM 
二进制  11000001     01001000      00000000      00000000 
十六进制   C1           48            00            00 
从这个例子可以得到下面的信息: 
  符号位是1 表示一个负数 
  幂是二进制10000010或十进制130,130减去127是3,就是实际的幂。 
  尾数是后面的二进制数10010000000000000000000 

在尾数的左边有一个省略的小数点和1,这个1在浮点数的保存中经常省略,加上一个1和小数 
点到尾数的开头,得到尾数值如下: 
1.10010000000000000000000 
接着,根据指数调整尾数.一个负的指数向左移动小数点.一个正的指数向右移动小数点.因为 
指数是3,尾数调整如下: 
1100.10000000000000000000 
结果是一个二进制浮点数,小数点左边的二进制数代表所处位置的2的幂,例如:1100表示 
(1*2^3)+(1*2^2)+(0*2^1)+(0*2^0)=12。 
小数点的右边也代表所处位置的2的幂,只是幂是负的。例如:.100…表示(1*2^(-1))+ 
(0*2^(-2))+(0*2^(-2))…=0.5。 
这些值的和是12.5。因为设置的符号位表示这数是负的,因此十六进制值0xC1480000表示- 
12.5。 
浮点数错误信息 
    8051没有包含捕获浮点数错误的中断向量,因此,你的软件必须正确响应这些错误情 
况。 
    除了正常的浮点数值,还包含二进制错误值。这些值被定义为IEEE标准的一部分并用在 
正常浮点数操作过程中发生错误的时候。你的代码应该在每一次浮点操作完成后检查可能出 
现的错误。 
        名称        值       含义 
        NaN     0xFFFFFFF   不是一个数 
        +INF    0x7F80000   正无穷(正溢出) 
        -INF    0xFF80000   负无穷(负溢出) 
    你可以使用如下的联合体(union)存储浮点数。 
    union f {
 

      float          f;  //浮点值 
      unsigned long ul;  //无符号长整数 
    }; 
    这个union包含一个float和一个unsigned long以便执行浮点数**算并响应IEEE错误 
状态。 
     
    以上是KEIL在线帮助的中译文,下面我们讨论如何显示浮点数。 
     
    尾数为24bit,最高可表达的整数值为2^24-1=16777215,也就是说,小于等于16777215 
的整数可以被精确显示。这决定了十进制浮点数的有效位数为7位,10^7<16777215<10^8, 
10的7次方以内的数小于16777215,可以精确表示。使用科学记数法时,整数部分占1位,所 
以小数部分最大占7-1=6位,即最大有6位十进制精度。 
    长整形数和浮点数都占4字节,但表示范围差别很大。浮点数的范围为+-1.175494E-38 
到+-3.402823E+38,无符号长整形数范围为0到4294967295。显示浮点数要用到长整形数保 
存数据,可他们范围差这么多,怎么办呢? 
    仔细观察十进制浮点数的显示,有一个尾数和一个阶码,由上面论证可知32位IEEE-754 
浮点数最大有效数字为7位十进制数,超出此范围的数字有截断误差,不必理会,因此,浮 
点数尾数能够放在长整形数里保存。阶码为-38到38,一个char型变量就可以保存。 
    综上所述,以10^7的最大跨度为窗口(小于10^7也可以,如:10,100…10000等,但决 
不能大于它,那样会超出精度范围),定位浮点数的量级,然后取出7位尾数的整数值存于长 
整形数里,再调整阶码,就可以精确显示此浮点数。 
    量级尺度如下: 
      (-38)-(-35)-(-28)-(-21)-(-14)-(-7)-(0)-(7)-(14)-(21)-(28)-(35)-(38) 
    请严格按照KEIL手册给出的浮点数范围显示,因为数值空间没有完全使用,有些值用于 
错误指示和表示正负无穷。小于1.175494E-38的数仍可以显示一些,但最好不用,以免出 
错。我采用直接判断的方法,剔除此种情况。 
    在计算机里结合律不成立,(a*b)*c!=a*(b*c),原则是先让计算结果值动态范围小的两 
个数运算,请注意程序里的写法。 
    注:(1E38/b)*1E6不要写成1E44/b,因为无法在32位浮点数里保存1E44,切记! 
    计算机使用二进制数计算,能有效利用电子器件高速开关的特性,而人习惯于十进制数 
表示,二进制和十进制没有方便的转换方法,只能通过大量计算实现,浮点数的十进制科学 
记数法显示尤其需要大量的运算,可见,显示一个浮点数要经过若干次浮点运算,没有必要 
就不要显示,否则,花在显示上的时间比计算的耗时都要多得多。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/149602.html原文链接:https://javaforall.net

(0)
上一篇 2022年6月24日 下午6:16
下一篇 2022年6月24日 下午6:16


相关推荐

  • PureMVC框架的学习笔记

    PureMVC框架的学习笔记参考资料 官方 GitHub 连接 https github com PureMVCPureM 官方网站 www puremvc org 博客 PureMVC 解析 Peter Gao 的博客 CSDN 博客 puremvc 曾经自己做的项目 UI 层使用简单的 UI 框架 发现扩展性不强 大型项目多人协同也是个问题 于是学习了比较经典的基于 MVC 的 PureMVC 以及基于 MVVM 的 LoxodonFrame 今天记录一下有关 PureMVC 的学习 MVC 思想什么是 MVC MVC 的全名是 Mo

    2026年3月17日
    2
  • oracle ebs 12.20 安装成功其过程失败日记及总结(1)

    oracle ebs 12.20 安装成功其过程失败日记及总结(1)

    2021年12月15日
    46
  • linux之alternatives管理多版本软件

    linux之alternatives管理多版本软件今天偶然间看到了 usr sbin alternatives 这个东西 感觉很陌生 于是学习了一番简单来说 比如系统中安装了多个版本的 jdk 那么怎么设置系统默认的 Jdk 呢 这个就是 alternatives 的功能 nbsp nbsp 学习过程 nbsp 1 首先在 linux 装了 1 8 版的 java 它被作为系统默认的 java root localhostcon java vers

    2026年1月19日
    1
  • 详解 Pytorch 实现 MNIST[通俗易懂]

    MNIST虽然很简单,但是值得我们学习的东西还是有很多的。项目虽然简单,但是个人建议还是将各个模块分开创建,特别是对于新人而言,模块化的创建会让读者更加清晰、易懂。CNN模块:卷积神经网络的组成;train模块:利用CNN模型对MNIST数据集进行训练并保存模型test模块:加载训练好的模型对测试集数据进行测试cnn.pt:train的CNN模型注意!有GPU的小伙伴尽量使用GPU训练,GPU的训练速度比CPU的训练速度高许多倍,可以节约大量训练时间CNN模块MN

    2022年4月8日
    86
  • Python里面数组拼接方法介绍

    Python里面数组拼接方法介绍numpy数组拼接方法介绍转载来源:https://blog.csdn.net/zyl1042635242/article/details/43162031数组拼接方法一思路:首先将数组转成列表,然后利用列表的拼接函数append()、extend()等进行拼接处理,最后将列表转成数组。示例1:>>>importnumpyasnp>>&g…

    2022年5月5日
    810
  • 【JAVA基础教程】java中异常机制总结

    【JAVA基础教程】java中异常机制总结

    2021年9月7日
    51

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号