IEEE754带正负极的浮点数编译与解析

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);

结果:

代码是本人独自匆匆实现的,不够简洁优美,能跑。如果有改进建议,欢迎跟我探讨!

----------------------------------------------------------------------------------------------------------------------

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程背景Modbus 协议是工业自动化控制系统中常见的通信协议,协议的全面理解是个痛点。本课程主讲老师集10多年在Modbus协议学习、使用中的经验心得,结合当前物联网浪潮下Modbus协议开发的痛点,推出这套面向Modbus 协议初学者的课程。本课程不同于以往市面课程只是协议讲解无实现代码,而是采用讲解与实践并重的方式,结合STM32F103ZET6开发板进行手把手编程实践,十分有利于初学者学习。涵盖了学习者在Modbus协议方面会遇到的方方面面的问题,是目前全网首个对Modbus协议进行全面总结的课程。课程名称   协议讲解及实现>>课程内容1、Modbus 协议的基础。2、Modbus协议栈函数编程实现。3、Modbus协议在串行链路编程实现。4、Modbus协议在以太网链路编程实现。5、常见问题的解决方法。给您的价值通过学习本课程,您可以做到如下:1、全面彻底的理解Modbus协议。2、理解在串行链路,以太网链路的实现。3、掌握Modbus协议解析的函数编程方法,调试工具的使用。4、掌握多个串口,网口同时运行同一个Modbus协议栈的方法。5、掌握Modbus协议下,负数,浮点数等处理方法。讲师简介许孝刚,山东大学工程硕士,副高职称,技术总监。10多年丰富嵌入式系统开发经验,国家软考“嵌入式系统设计师”。2017年获得“华为开发者社区杰出贡献者”奖励。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值