IEEE754格式:
符号位 指数位 尾数位 指数偏移量
32位 1[31] 8[23-30] 23[0-22] 127
64位 1[63] 11[52-62] 52[0-51] 1023
32位 说明:
1位符号位(SIGN) 存储正负极 0:+ 1:-
8位指数位(EXPONENT) 存储幂
23位尾数位(MANTISSA) 存储二进制值正文
------------------------------------------------------------------------------------------
JAVA库实现方法
/**
* 十六进制转十进制浮点数
*/
public static float hexToFloat(String hex) {
return Float.intBitsToFloat(new BigInteger(hex, 16).intValue());
}
/**
* 十进制浮点数转十六进制
*/
public static String floatToHex(float floatValue) {
int hexInt = Float.floatToIntBits(floatValue);
return Integer.toHexString(hexInt);
}
------------------------------------------------------------------------------------------
下面是本人实现的:
废话不多说,直接上代码(Java):包括 生成与解析
/**
* Modbus协议 IEEE754
* IEEE754 32位 : 带正负的浮点数转换
* @author LT
*/
public class ModbusUtilsOfIEEE754 {
/**
* 解析
*
* @param str ******** 8位
* @return double
*
*/
public static double parseModbusDouble(String str) {
int intSign, Exponent, intExponent;
double faResult, intMantissa;
if (str.equals("00000000")) {
return 0; //为0,提前抛出
}
//高低位处理与十六进制转二进制
String binary1 = hexString2binaryString(str.substring(0, 4));
String binary2 = hexString2binaryString(str.substring(4, 8));
binary1 = addZeroForNum(binary1, 16, "left"); //规范格式到16位 将空位补0
binary2 = addZeroForNum(binary2, 16, "left");
String binary = binary1 + binary2; //高低位二进制拼接 左高右低
//抓取参数
intSign = Integer.parseInt(binary.substring(0, 1)); //正负位
Exponent = Integer.parseInt(binary.substring(1, 9)); //8位指数位
intExponent = Integer.parseInt(String.valueOf(Exponent), 2);
//计算
StringBuilder mantissa = new StringBuilder("1" + binary.substring(9, 32));//mantissa首部加 1.
int move = intExponent - 127 + 1;//-127 幂偏移量 ,+1 是弥补上面漏掉的小数点
int length = mantissa.length();
if (move > length) {
for (int i = 0; i < move - length; i++) {
mantissa.append("0");
}
} else if (move < 0) {
for (int i = 0; i >= move; i--) {
mantissa.insert(0, "0");
}
mantissa.insert(1, ".");
} else {
mantissa.insert(move, ".");
}
intMantissa = getBinaryToDouble(mantissa.toString());
//计算公式
faResult = Math.pow(-1, intSign) * intMantissa;
faResult = (double) Math.round(faResult * 10000) / 10000; //四舍五入取小数点后四位,减小精度干扰
return faResult;
}
/**
* 生成
*
* @param value
* @return String ******** 8位
*/
public static String createModbusDouble(double value) {
String sign = "0";
String mantissa, exponent;
//十进制转二进制
if (value < 0) { //负数
sign = "1";
} else if (value == 0) {
return "00000000"; //为0,抛出
}
String binary = getDoubleToBinary(String.valueOf(Math.abs(value)));
int n = binary.indexOf(".") - 1;
if (binary.endsWith(".0")) { //整数
binary = binary.replace(".0", ""); //去掉 .0
} else { //小数
binary = binary.replace(".", ""); //去掉 .
}
int length = binary.length();
if (length < 24) {
binary = addZeroForNum(binary, 24, "right");//补0
}
if (binary.startsWith("1")) { //开头有1时
//去掉首位 1 ,只取 23 长度。由于协议只能存储23位二进制的正文,所以会出现精度问题。解析时我采用四舍五入保留了小数点后四位,减小精度干扰!
mantissa = binary.substring(1, 24);
} else {//开头无1时,即整数部分为0,需要位移到有第一个1处再去掉1,n相应变化
int index = binary.indexOf("1", 1);
// if(index >= 0) { //不存在1,即为value = 0,上面已排除
mantissa = binary.substring(index + 1, index + 25);
n = n - index;
// }
}
exponent = getDoubleToBinary(String.valueOf(n + 127));
exponent = exponent.replace(".0", "");
exponent = addZeroForNum(exponent, 8, "left");//补0
String result = sign + exponent + mantissa;
result = binaryToHex(result.substring(0, 16), 4) + binaryToHex(result.substring(16, 32), 4);
return result;
}
/**
* 将二进制转换为十进制浮点数
*
* @param str
* @return
*/
public static double getBinaryToDouble(String str) {
//把输入的字符串分成整数部分s1和小数部分s2
int n = str.indexOf(".");
if (n < 0) {
str += ".0";
n = str.indexOf(".");
}
String s1 = str.substring(0, n);
String s2 = str.substring(n + 1);
return sToInt(s1) + sToDou(s2);
}
//把整数部分转成double
static int sToInt(String s) {
if (s.length() == 1) return s.charAt(0) - '0';
return sToInt(s.substring(0, s.length() - 1)) * 2
+ (s.charAt(s.length() - 1) - '0');
}
//把小数部分转成double
static double sToDou(String s) {
if (s.length() == 1) return (s.charAt(0) - '0') / 2.0;
return (s.charAt(0) - '0') / 2.0 + sToDou(s.substring(1)) / 2.0;
}
/**
* 将十进制浮点数转换为二进制
*
* @param s
* @return
*/
static String getDoubleToBinary(String s) {
int n = s.indexOf(".");
if (n < 0) {
s += ".0";
n = s.indexOf(".");
}
String s1 = s.substring(0, n);
String s2 = "0" + s.substring(n);
String s3 = intToStr(Integer.parseInt(s1));
String s4 = dToStr(Double.parseDouble(s2));
return (s3.length() == 0 ? 0 : s3) + "." + s4;
}
//把整数部分转成二进制
static String intToStr(int n) {
if (n == 0) return "";
int a = n % 2;
int b = n / 2;
return intToStr(b) + a;
}
//把小数部分转成二进制
static String dToStr(double d) {
if (d - (int) d < 0.01) return "" + (int) d;
int n = (int) (d * 2);
double a = d * 2 - n;
return "" + n + dToStr(a);
}
/**
* 将16进制转换为二进制
*
* @param hexString
* @return
*/
public static String hexString2binaryString(String hexString) {
if (hexString == null || hexString.length() % 2 != 0)
return null;
String bString = "", tmp;
for (int i = 0; i < hexString.length(); i++) {
tmp = "0000"
+ Integer.toBinaryString(Integer.parseInt(hexString
.substring(i, i + 1), 16));
bString += tmp.substring(tmp.length() - 4);
}
return bString;
}
/**
* 将二进制转换成16进制
*
* @param str
* @return
*/
public static String binaryToHex(String str, int length) {
String result = String.format("%X", Long.parseLong(str, 2));
int l = length - result.length();
if (l > 0) {
for (int i = l; i >= 0; i--) {
result = "0" + result; //前面追加0
}
}
return result;
}
/**
* 字符串补0
*
* @param str
* @param strLength
* @return
*/
public static String addZeroForNum(String str, int strLength, String direction) {
int strLen = str.length();
if (strLen < strLength) {
while (strLen < strLength) {
StringBuffer sb = new StringBuffer();
if ("left".equals(direction)) {
sb.append("0").append(str);// 左补0
} else if ("right".equals(direction)) {
sb.append(str).append("0");//右补0
}
str = sb.toString();
strLen = str.length();
}
}
return str;
}
}
调用方式:
double x = -0.4526;
String str = ModbusUtilsOfIEEE754.createModbusDouble(x); //生成16进制高低位指令
double y = ModbusUtilsOfIEEE754.parseModbusDouble(str); //解析
System.out.println(str);
System.out.println(y);
结果:
代码是本人独自匆匆实现的,不够简洁优美,能跑。如果有改进建议,欢迎跟我探讨!
----------------------------------------------------------------------------------------------------------------------