[Java SE] 经典问题:超出Java Long型(8字节/64位)的二进制比特流数据如何进行大数的数值计算?

0 问题描述

  • 经典问题:超出Java Long型(8字节/64位)的二进制比特流数据如何进行大数的数值计算?

近期工作上遇到了这个问题:需要将一个无符号数、且位长>=8字节(等于8字节时,首位bit为1,其他bit不全为0)的二进制字符串 转为Java****对象(原始整数 ),进行整型 运算、或浮点数运算

浮点运算的思路:result = 原始整数 * 精度 + 偏移量

  • 解决思路:将二进制字符串转为byte数组,再转为BigInteger大整型数。如果基于进行浮点运算时,可将 BigInteger 大整型数对象再转为 BigDecimal。

new BigDecimal v = new BigDecimal(new BigInteger(xxx))

1 解决过程示例

  • 二进制数据:"1100000001000000110010110000000000000000000000000000000000000000" (需考虑------------情况1:作为有符号数情况2:作为无符号数

16进制:0xc040cb0000000000L

shell 复制代码
11000000 
01000000
11001011
00000000
00000000
00000000
00000000
00000000

1.1 测试用例1:无符号数、且位长>=8字节(等于8字节时,首位bit为1,其他bit不全为0)的情况

java 复制代码
    /** 针对 长度为 64 bit、无符号数 的CAN信号,且第1位为1的情况 :使用 BigInteger
     * @description Java中没有内置的无符号8字节整数类型,但是可以使用 `java.math.BigInteger` 类来处理任意大的整数值,包括无符号整数
     * @refernce-doc
     **/
    public static void unsigned8BytesDataTest(){
        // 一个8字节的无符号整数
        long longValue =  0xc040cb0000000000L; //0x10000000000000000L;
        String longStr = "c040cb0000000000";//canFrameContent
        // 转为二进制字符串
        String binStr = BytesUtil.hexStringToBinaryString(longStr);
        System.out.println("binStr: " + binStr);//1100000001000000110010110000000000000000000000000000000000000000

        // 将无符号长整数转换为 BigInteger | 方式1: BigInteger
        BigInteger value = toUnsignedBigInteger(longValue);
        System.out.println("value : " + value);//1385 3295 6546 5208 4224

        //二进制字符串转Java数据对象 | 测验 Long.parseLong(binStr , 2) | 若没有报错,则说明OK
        BigInteger value2 = toUnsignedBigInteger(binStr);
        System.out.println("value2 : " + value2);//1385 3295 6546 5208 4224

        //二进制字符串转Java数据对象 | 测验 Long.parseLong(binStr , 2) | 若没有报错,则说明OK
        Long value3 = Long.parseLong(binStr, 2);
        System.out.println("value3 : " + value3);//报错信息如下
//        Exception in thread "main" java.lang.NumberFormatException: For input string: "1100000001000000110010110000000000000000000000000000000000000000"
//        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
//        at java.lang.Long.parseLong(Long.java:592)
//        at ParseTest.unsigned8BytesDataTest(ParseTest.java:213)
//        at ParseTest.main(ParseTest.java:29)
        }

1.2 测试用例2:有符号数、且位长>=8字节(等于8字节时,首位bit为1,其他bit不全为0)的情况

java 复制代码
    /**
     * 有符号数、8字节
     * 最终目标: 二进制字符串 转 Java 数据对象
     */
    public static void signed8BytesDataTest(){
        // 一个8字节的无符号整数
        long longValue =  0xc040cb0000000000L; //0x10000000000000000L;
        String longStr = "c040cb0000000000";//canFrameContent
        // 转为二进制字符串
        String binStr = BytesUtil.hexStringToBinaryString(longStr);
        System.out.println("binStr: " + binStr);//1100000001000000110010110000000000000000000000000000000000000000

        // 将有符号长整数转换为 BigInteger | 方式1: BigInteger
        BigInteger value = toUnsignedBigInteger(longValue);
        System.out.println("value : " + value);//-459 3448 4190 5746 7392

        //二进制字符串转Java数据对象 | 测验 Long.parseLong(binStr , 2) | 若没有报错,则说明OK
        BigInteger value2 = toUnsignedBigInteger(binStr);
        System.out.println("value2 : " + value2);//1385 3295 6546 5208 4224

        //二进制字符串转Java数据对象 | 测验 Long.parseLong(binStr , 2) | 若没有报错,则说明OK
        Long value3 = Long.parseLong(binStr, 2);
        System.out.println("value3 : " + value3);//报错信息如下
//        Exception in thread "main" java.lang.NumberFormatException: For input string: "1100000001000000110010110000000000000000000000000000000000000000"
//        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
//        at java.lang.Long.parseLong(Long.java:592)
//        at ParseTest.signed8BytesDataTest(ParseTest.java:241)
//        at ParseTest.main(ParseTest.java:30)
    }

1.X 工具方法

toUnsignedBigInteger(long unsignedLong/String binStr)

java 复制代码
    private static BigInteger toUnsignedBigInteger(long unsignedLong) {
        // 将无符号的8字节长整数转换为字节数组
        byte[] bytes = ByteBuffer.allocate(8).putLong(unsignedLong).array();

        // 使用字节数组创建BigInteger
        return new BigInteger(1, bytes);
    }

    /** 二进制字符串 **/
    private static BigInteger toUnsignedBigInteger(String binStr) {
        byte[] bytes = null;
        try {
            // 将无符号的8字节长整数转换为字节数组
            bytes = BytesUtil.binaryStringToBinaryArray(binStr);
        } catch (Exception exception) {
            log.error("Fail to convert as big integer!binStr : {}, exception : {}", binStr, exception);
        }

        // 使用字节数组创建BigInteger
        return new BigInteger(1, bytes);
    }

binaryStringToBinaryArray(binStr)

java 复制代码
    /**
     * 二进制字符串转二进制数组
     * @param binaryString
     * @return
     */
    public static byte[] binaryStringToBinaryArray(String binaryString) {
        if(ObjectUtils.isEmpty(binaryString)){
            throw new RuntimeException("Fail to convert binary array cause by the empty binary string! binaryString : " + binaryString);
        }
        if(binaryString.length() %8 != 0){//不是8的倍数
            throw new RuntimeException("Fail to convert binary array cause that the binary string is not a multiple of 8! binaryString : " + binaryString);
        }

//        char [] charArray =  binaryString.toCharArray() // string 内部由 2个字节的char组成的 char 数组 , 故: 这种转换做法有风险
//        byte [] binaryArray = new byte [ binaryString.length() ];
//        for (int i = 0; i < charArray.length; i ++) {
//            //binaryArray[i] = (byte)charArray[i]; // java char 占用 : 2个字节 ; java byte 占用 1个字节 => 这种做法不正确
//            binaryArray[i]
//        }

        int byteSize = binaryString.length()/8;
        byte[] binaryArray = new byte[byteSize];
        for (int i = 0; i < byteSize; i ++) {
            String byteBinaryStr = binaryString.substring(i*8, i*8 + 8);//sample "01001000"
            binaryArray[i] = binaryStringToByte(byteBinaryStr);
        }
        return binaryArray;
    }

X 参考文献

相关推荐
编程彩机3 天前
互联网大厂Java面试:从Java SE到大数据场景的技术深度解析
java·大数据·spring boot·面试·spark·java se·互联网大厂
编程火箭车4 天前
【Java SE 基础学习打卡】37 二维数组
二维数组·数组遍历·java se·java 基础·二维数组初始化·不规则二维数组·表格型数据存储
编程火箭车14 天前
【Java SE 基础学习打卡】36 数组的常见操作
冒泡排序·java se·java 基础·线性查找·数组常见操作·数组增删改·数组拷贝
编程火箭车15 天前
【Java SE 基础学习打卡】35 数组元素的访问与遍历
数组索引·java se·java 基础·java 数组·数组元素访问与遍历·普通 for 循环·增强 for 循环
编程火箭车18 天前
【Java SE 基础学习打卡】34 数组的定义与初始化
java se·java 基础·java 数组·数组定义与初始化·静态初始化·动态初始化·length 属性
编程火箭车19 天前
【Java SE 基础学习打卡】33 数组的概述
java se·java 基础·数组概述·数组核心特征·java 数组·批量存储数据·连续内存存储
编程火箭车20 天前
【Java SE 基础学习打卡】32 方法的嵌套调用与递归调用
java se·java 基础·java 方法·方法嵌套调用·方法递归调用·递归终止条件·递归应用场景
编程火箭车21 天前
【Java SE 基础学习打卡】31 方法的返回值与void关键字
java se·java 基础·return 语句·编程小白入门·java 方法·方法返回值·void 关键字
编程火箭车23 天前
【Java SE 基础学习打卡】28 方法的定义与调用
java se·参数传递·返回值·java 基础·新手避坑·java 方法·方法定义与调用
编程火箭车1 个月前
【Java SE 基础学习打卡】27 方法的概述
编程语法·java se·代码复用·编程小白入门·方法概述·功能模块化·java 方法