#2
csyx2023-08-27 16:02
|
本人使用VFP做上位机开发了一个远程抄表程序,终端设备使用 MODBUS RTU 协议,数据为浮点型,于是编写了一个10进制与16进制浮点型数据转换函数,但是转换结果不知正确与否,例如,10进制数22.5转换16进制浮点数为41B46660,而这个16进制数在还原回去为22.5499877929687500,不知道是否正确,请大侠指点。
附两个函数,不打包了,直接复制粘贴到VFP即可使用。
*浮点型数据十进制转换十六进制浮点型数据
*依据IEEE-754标准
*八位HEX数据转换成32位二进制数据后从高位至低位分为3个部分
*S-第1位,符号位,0为正数,1为负数
*E-第2至9位,指数位,浮点的位置,数值减去127所得
*M-第10至32位,数据位,由整数和小数组成
*函数名:FDX_DECTOHEX
*用法:FDX_DECTOHEX(浮点数值) &&数值型,返回字符型
Function FDX_DECtoHEX
LPARAMETER DEC_SJ
*1-判别符号+/-S
IF DEC_SJ>0
S="0"
ELSE
S="1"
DEC_SJ=ABS(DEC_SJ)
ENDIF
*分解数据为整数和小数
*整数部分
SJ1=INT(DEC_SJ)
*小数部分
SJ2=DEC_SJ-SJ1
*整数部分转二进制,除2取余
FOR I=1 TO 32
X1=SJ1/2
X2="ZS"+ALLTRIM(STR(I))
&X2=SJ1%2
SJ1=INT(X1)
IF SJ1=0
EXIT
ENDIF
ENDFOR
X2=I
X3=I
X4=""
FOR I=1 TO X2
X5="ZS"+ALLTRIM(STR(X3))
X4=X4+ALLTRIM(STR(&X5))
X3=X3-1
ENDFOR
ZSBF=X4
X2=""
*小数部分转二进制,乘2取整
FOR I=1 TO 16
X1="XS"+ALLTRIM(STR(I))
SJ2=SJ2*2
X2=X2+ALLTRIM(STR(INT(SJ2)))
IF SJ2>0
SJ2=SJ2-INT(SJ2)
ENDIF
ENDFOR
XSBF=X2
M=SUBSTR(ZSBF,2)+XSBF
*计算指数E
E1=LEN(ZSBF)-1+127
SJ1=E1
FOR I=1 TO 32
X1=SJ1/2
X2="ZS"+ALLTRIM(STR(I))
&X2=SJ1%2
SJ1=INT(X1)
IF SJ1=0
EXIT
ENDIF
ENDFOR
X2=I
X3=I
X4=""
FOR I=1 TO X2
X5="ZS"+ALLTRIM(STR(X3))
X4=X4+ALLTRIM(STR(&X5))
X3=X3-1
ENDFOR
E=X4
M=SUBSTR(ZSBF,2)+XSBF
M=PADR(M,23,"0")
FDSJ2=S+E+M
FDSJ16=""
XX=1
*二进制转十六进制
FOR I=1 TO 8
SJ16=SUBSTR(FDSJ2,XX,4)
DO CASE
CASE SJ16="0000"
FDSJ16S="0"
CASE SJ16="0001"
FDSJ16S="1"
CASE SJ16="0010"
FDSJ16S="2"
CASE SJ16="0011"
FDSJ16S="3"
CASE SJ16="0100"
FDSJ16S="4"
CASE SJ16="0101"
FDSJ16S="5"
CASE SJ16="0110"
FDSJ16S="6"
CASE SJ16="0111"
FDSJ16S="7"
CASE SJ16="1000"
FDSJ16S="8"
CASE SJ16="1001"
FDSJ16S="9"
CASE SJ16="1010"
FDSJ16S="A"
CASE SJ16="1011"
FDSJ16S="B"
CASE SJ16="1100"
FDSJ16S="C"
CASE SJ16="1101"
FDSJ16S="D"
CASE SJ16="1110"
FDSJ16S="E"
CASE SJ16="1111"
FDSJ16S="F"
ENDCASE
FDSJ16=FDSJ16+ FDSJ16S
XX=XX+4
ENDFOR
*返回计算结果
RETURN FDSJ16
ENDFUNC
*****************************************************
*函数名:FDX_HEXTODEC
*用法:FDX_HECTODEC("8位16进制数") &&字符型,返回数值型
Function FDX_HEXTODEC
LPARAMETER HEX_SJ
FDSJ=0
B1=LEN(ALLTRIM(HEX_SJ))
IF B1 <>8
RETURN FDSJ
ENDIF
HEX_SJ=UPPER(HEX_SJ)
* 16进制转换2进制
HEX_SJ_2=""
FOR i=1 TO b1
f_x1=SUBSTR(HEX_SJ,i,1)
DO CASE
CASE f_x1="0"
x="0000"
CASE f_x1="1"
x="0001"
CASE f_x1="2"
x="0010"
CASE f_x1="3"
x="0011"
CASE f_x1="4"
x="0100"
CASE f_x1="5"
x="0101"
CASE f_x1="6"
x="0110"
CASE f_x1="7"
x="0111"
CASE f_x1="8"
x="1000"
CASE f_x1="9"
x="1001"
CASE f_x1="A"
x="1010"
CASE f_x1="B"
x="1011"
CASE f_x1="C"
x="1100"
CASE f_x1="D"
x="1101"
CASE f_x1="E"
x="1110"
CASE f_x1="F"
x="1111"
ENDCASE
HEX_SJ_2=HEX_SJ_2+x
ENDFOR
SJ=SUBSTR(HEX_SJ_2,10)&&符号位,0为正数
DW=SUBSTR(HEX_SJ_2,2,8)&&指数位,小数点位置
FH=VAL(SUBSTR(HEX_SJ_2,1,1))&&数据位
*计算指数
a0=0
a1=DW
a2=LEN(a1)
FOR i=0 TO a2-1
a3=SUBSTR(a1,a2-i,1)
a4=VAL(a3)*2^i
a0=a0+a4
ENDFOR
ZS=A0-127
*计算数据
a0=0
a1=SJ
a2=LEN(a1)
X=0
FOR i=1 TO a2
x=X-1
a3=SUBSTR(a1,i,1)
a4=VAL(a3)*2^x
a0=a0+a4
ENDFOR
FDSJ=(-1^FH)*(1+A0)*2^ZS
RETURN FDSJ
ENDFUNC
***************************************************************************************