Float在内存中的存储方式及IEC61131处理

1,fp32(32bits float)类型数据在存储器中占用4Bytes存储,且遵循IEEE-754标准:

一个浮点数分三部分组成:

符号位s(1bit: 31b)+指数e(8bits: -23b)+底数m(23bits: -0b)

2,符号位s

Bit31表示符号位,符号位指数值的正负,0表示正数,1表示负数。

3,指数e

bit30-23,8bits表示一个有符号的指数,他是十进制指数加上127所得的 数值。

所以我们计算指数的时候必须减去127。

4,底数m

Bit22-0,23bits表示实际存储的底数。

底数实际占用的是24bits的数据位,由于最高位始终为1,所以不显式显示。

5,举例

0.1:

转换为二进制=0.00001

科学计数表示=1.0*2^-1

S=0

E=-1+127=126=0111 1110b

M=000 0000 _ 0000 0000 0000 0000

0011 1111 0000 0000 _ 0000 0000 0000 0000

1.0:

转换为二进制=1.0

科学计数表示=1.0*2^0

S=0

E=0+127=127=0111 1111b

M=000 0000 _ 0000 0000 0000 0000

0011 1111 1000 0000 _ 0000 0000 0000 0000

3.0:

转换为二进制=11.0

科学计数表示=1.1*2^1

S=0

E=1+127=128=1000 0000b

M=100 0000 _ 0000 0000 0000 0000

0100 0000 0100 0000 _ 0000 0000 0000 0000

10.0:

转换为二进制=1010.0

科学计数表示=1.01*2^3

S=0

E=3+127=130=1000 0010b

M=010 0000 _ 0000 0000 0000 0000

0100 0001 0010 0000 _ 0000 0000 0000 0000

-10.0:

转换为二进制=-1010.0

科学计数表示=-1.01*2^3

S=1

E=3+127=130=1000 0010b

M=010 0000 _ 0000 0000 0000 0000

1100 0001 0010 0000 _ 0000 0000 0000 0000

1.625:

转换为二进制=1.101

科学计数表示=1.101*2^0

S=0

E=0+127=127=0x7F=0111 1111b

M=101 0000_0000 0000 0000 0000

0011 1111 1101 0000_0000 0000 0000 0000

实际代码操作中,我们对fp32进行手动编码操作的过程如下:

  • 考虑到0的特殊性,对0作单独处理。
  • 非零值,底数均要转化为1.x * 2 ^e。
  • 定义指数e=0;先把原始数据转码:

大于2的除2,直到小于2为止,每次操作均要e++

小于1的乘2,直到大于1为止,每次操作均要e--

  • 此时我们已经取到了指数e,e+127就是我们指数域的数值了。

下面是取指的操作过程:

 (*    小于1不为0的数据, 直接放大到>        *)
WHILE (real_data < .) AND (real_data <> .) DO
real_data := real_data * .;
temp_E := temp_E - ;
END_WHILE;
(* 大于2的数据, 直接缩小至< *)
WHILE (real_data > .) DO
real_data := real_data / .;
temp_E := temp_E + ;
END_WHILE;

temp_E就是我们得到的实际指数。

  • 此时的底数为1.x,由于1固定不写,所以我们把小数部分0.x转化为二进制数值,左对齐,写入到码值的22..0数据域即可。
  • 循环体以小数码值不为0 与 数据域23bits写满作为条件。
  • 小数部分每次乘2,记录整数部分是否为1,为1的话当前对应的bit写1。
  • 更新小数部分的值,更新当前的置位位置。
  • 取整数的过程,需要考虑不同平台的差异性,避免由于四舍五入出错。

下面是我用IEE61131 ST编写的取底数操作:

 (* , 计算底数, bit22..                    *)
int_pos := ; (* 第一个小数位的起始点 *)
IF real_data <> . THEN
real_dec := real_data - .;
ELSE
real_dec := .;
END_IF; WHILE (real_dec > .) AND (int_pos > -) DO
real_tmp := real_dec * .;
(* 判断是否是1 *)
real_int := REAL_TO_UDINT(real_tmp - .);
IF real_int > UDINT# THEN
real_dec := real_tmp - .;
temp_M := temp_M + SHL_DWORD(DWORD#, int_pos);
ELSE
real_dec := real_tmp;
END_IF;
int_pos := int_pos - ;
END_WHILE;

temp_M就是最后计算的底数码值。

6,解码计算浮点过程是对上述操作的反向定义,相对比较容易写。

7,我们可以分指数、整数和小数分别解析。

8,指数直接取出即可

 (* , 解析指数: bit30..            *)
t_E := DWORD_TO_INT(SHR_DWORD(UDINT_TO_DWORD(code32), ) AND DWORD##FF);
IF t_E <> THEN
t_E := t_E - ;
END_IF;

9,整数部分

指数为正的乘2累加,比如:1010

1 -> 1

0 -> 1*2+0=2

1 -> 2*2+1=5

0 -> 5*2+0=10

指数为负的除2累加,结果累加到小数。

 (* , 计算整数部分数据                *)
bTemp := t_E;
IF bTemp < INT# THEN
t_Int := UDINT#;
t_Dec := .;
WHILE bTemp < DO
bTemp := bTemp + ;
t_M := t_M / UDINT#;
t_Dec := t_Dec / .;
END_WHILE;
ELSE
t_Int := UDINT#;
t_Dec := .;
WHILE bTemp > DO
t_Int := t_Int * UDINT#;
IF (UDINT_TO_DWORD(t_M) AND DWORD##) <> DWORD# THEN
t_Int := t_Int + UDINT#;
END_IF;
bTemp := bTemp - ;
t_M := t_M * UDINT#;
END_WHILE;
END_IF;

10,小数部分除2累加,比如:101

1 -> 1/2=0.5

0 -> 0.5+0=0.5

1 -> 0.5+1/8=0.625

 (* , 计算小数部分数据                *)
factor := .;
WHILE t_M > UDINT# DO
IF (UDINT_TO_DWORD(t_M) AND DWORD##) <> DWORD# THEN
t_Dec := t_Dec + . / factor;
END_IF;
factor := factor * .;
t_M := t_M * UDINT#;
END_WHILE;

11,最后根据符号位调整数值结果即可。

12,同时要注意的是码值为0的时候直接浮点为0.0即可。

Float在内存中的存储方式及IEC61131处理的更多相关文章

  1. <转载>浅谈C/C++的浮点数在内存中的存储方式

    C/C++浮点数在内存中的存储方式 任何数据在内存中都是以二进制的形式存储的,例如一个short型数据1156,其二进制表示形式为00000100 10000100.则在Intel CPU架构的系统中 ...

  2. C语言中浮点数在内存中的存储方式

    关于多字节数据类型在内存中的存储问题 //////////////////////////////////////////////////////////////// int ,short 各自是4. ...

  3. QList介绍(QList比QVector更快,这是由它们在内存中的存储方式决定的。QStringList是在QList的基础上针对字符串提供额外的函数。at()操作比操作符[]更快,因为它不需要深度复制)非常实用

    FROM:http://apps.hi.baidu.com/share/detail/33517814 今天做项目时,需要用到QList来存储一组点.为此,我对QList类的说明进行了如下翻译. QL ...

  4. C语言 float、double数据在内存中的存储方式

    float在内存中占4个字节(32bit),32bit=符号位(1bit)+指数位(8bit)+底数位(23bit) 指数部分 指数位占8bit,可以表示数值的范围是0-(表示0~255一共256个数 ...

  5. float 在内存中如何存储的

    float类型数字在计算机中用4个字节存储.遵循IEEE-754格式标准:    一个浮点数有2部分组成:底数m和指数e 底数部分 使用二进制数来表示此浮点数的实际值指数部分 占用8bit的二进制数, ...

  6. 数据在内存中的存储方式( Big Endian和Little Endian的区别 )(x86系列则采用little endian方式存储数据)

    https://www.cnblogs.com/renyuan/archive/2013/05/26/3099766.html 1.故事的起源 “endian”这个词出自<格列佛游记>.小 ...

  7. float和double在内存中的存储方式

    本文转载于:http://wenku.baidu.com/link?url=ARfMiXVHCwCZJcqfA1gfeVkMOj9RkLlR9fIexbgs9gDdV8rIS48A1_xe1y6YgX ...

  8. C/C++浮点数在内存中的存储方式

    一.内存表示 任何数据在内存中都是以二进制的形式存储的,浮点数的表示是把一个数的有效数字和数的范围在计算机的一个存储单元中分别予以表示,数的小数点位置随比例因子的不同而在一定范围内自由浮动.如下图是3 ...

  9. C++成员函数在内存中的存储方式

    用类去定义对象时,系统会为每一个对象分配存储空间.如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间.按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分 ...

随机推荐

  1. 爬虫 - 请求库之selenium

    介绍 官方文档 selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题 selenium本质是通过驱动浏览器,完全模拟浏览器的 ...

  2. BM递推杜教版【扩展】

    也就是模数不是质数的时候, //下面的板子能求质数和非质数,只需要传不同的参数. #include <cstdio> #include <cstdlib> #include & ...

  3. 回文数 js 解法

    判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 示例 1: 输入: 121 输出: true 示例 2: 输入: -121 输出: false 解释: 从左向 ...

  4. [译]深度神经网络的多任务学习概览(An Overview of Multi-task Learning in Deep Neural Networks)

    译自:http://sebastianruder.com/multi-task/ 1. 前言 在机器学习中,我们通常关心优化某一特定指标,不管这个指标是一个标准值,还是企业KPI.为了达到这个目标,我 ...

  5. Spring Cloud Gateway(十一):全局过滤器GlobalFilter

    本文基于 spring cloud gateway 2.0.1 1.简介 GlobalGilter 全局过滤器接口与 GatewayFilter 网关过滤器接口具有相同的方法定义.全局过滤器是一系列特 ...

  6. java 73题以及答案

    作者:乌枭原文:https://blog.csdn.net/qq_34039315/article/details/78549311 1.在java中守护线程和本地线程区别? java中的线程分为两种 ...

  7. NIO Channel SocketChannel ServerSocketChannel

    ServerSocketChannel: ServerSocketChannel是一个基于通道的socket监听器.它同我们所熟悉的java.net.ServerSocket执行相同的基本任务,不过它 ...

  8. SSL 安全协议 以及 如何认证

    目录 ssl安全协议 以及 认证 什么是协议 http劫持 ssl是什么 ssl 证书 概念 3种类型ssl 证书 ssl认证:阿里云免费认证 配置 Nginx的ssl认证 nginx的ssl证书(一 ...

  9. 第12组 Beta冲刺(5/5)

    Header 队名:To Be Done 组长博客 作业博客 团队项目进行情况 燃尽图(组内共享) 展示Git当日代码/文档签入记录(组内共享) 注: 由于GitHub的免费范围内对多人开发存在较多限 ...

  10. crontab定时任务接入

    # 查看 $ crontab -l # 创建 $ crontab -e # 每分钟输出一次当前时间 * * * * * echo `date` >> /demo.log # 查看定时 $ ...