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

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

时间:2024-04-13 17:24:32浏览次数:27  
标签:BigInteger Java 字节 二进制 比特流 Long java binStr

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

11000000 
01000000
11001011
00000000
00000000
00000000
00000000
00000000

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

    /** 针对 长度为 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)的情况

    /**
     * 有符号数、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)

    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)

    /**
     * 二进制字符串转二进制数组
     * @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 参考文献

标签:BigInteger,Java,字节,二进制,比特流,Long,java,binStr
From: https://www.cnblogs.com/johnnyzen/p/18133094

相关文章

  • Java中的各种引用类型以及部分引用的相关例子
    在Java中,引用类型主要有四种,分别是:强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)和虚引用(PhantomReference)。这些类型通常与垃圾回收机制有关,用来描述对象的生命周期和可达性。下面详细介绍每一种引用类型:强引用(StrongReference)强引用是最常见的引用......
  • 记录协助Javaer硬件快速开发过程之Web技术栈对接施耐德网络IO网关
    前一段时间有个Java技术栈的朋友联系到我,需要快速对接现有的无人值守称重系统,这里的对接是指替代现有系统,而非软件层面的对接,也就是利用现有的硬件开发一套替代现有软件的自动化系统。主要设备包括地磅秤、道闸、红外对射传感器、摄像头、小票打印、LED显示屏等等,全程使用LED显示......
  • java的两个bean之间复制属性,所有属性中替换某几个字符
    以下是实现代码:importjava.beans.PropertyDescriptor;importjava.lang.reflect.InvocationTargetException;importjava.util.ArrayList;importjava.util.List;importorg.springframework.beans.BeanUtils;publicclassBeanCopyUtil{/***复制bean属性......
  • 在Windows安装javaSE8
    1.下载安装官网Java1.8_31.zip2.配置环境变量创建.bat文件,写入以下内容后执行。自动配置环境变量@echooff%1mshtavbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe","/c%~s0::","","runas",1)(window.close)&&exit......
  • JAVA 板子
    代码片段1importjava.io.BufferedReader;importjava.io.BufferedWriter;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.OutputStreamWriter;importjava.io.PrintWriter;importjava.io.StreamTokenizer;publicclassMain{stati......
  • java代码审计-sqli
    Java代码审计-sqli0x01漏洞挖掘jdbc在上古时期,人们往往这么从数据库获取数据。publicUsergetUserById(Stringid)throwsSQLException{Connectionconnection=JDBCTOOLS.getConnection(); Stringsql="selectid,usernamefromuserwhereid="+id; State......
  • java代码审计-反序列化
    Java代码审计-反序列化0x00漏洞挖掘业务代码简单来说,找readObject/readUnshared就好了protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{StringbaseStr=request.getParameter("str");b......
  • Java基础知识篇02——封装
    大家好,我是白夜,今天给大家聊聊面向对象的三大特征——封装一、包(package)1.1、包的引入先来看看我们之前写的代码结构以上代码存在的问题所有类写在一个目录下面,非常难管理,因为以后项目不可能只有这么几个类,当类数量很大的时候,就不容易管理了。不能写同名但是不同需求的类......
  • Java如何自行实现正向地理编码算法(不依赖api,不联网)
    政务场景中经常会遇到地址落图,或者三维挂接的场景。如何将文本地址转化为gps坐标是实现要解决的核心问题。addresstool为正向地理编码提供了非常简单、高效的算法。如何实现正向地理编码,只需要3步就行:第一步:带有坐标的标准地址加载到addresstool中。第二部:以业务地址作为参数,使......
  • java 怎么把负数变正数
    java怎么把负数变正数Java中将负数变为正数可以通过以下几种方式实现:使用绝对值函数、使用三目运算符、使用位运算或者使用移位运算。下面将详细介绍这些方法。1.使用绝对值函数Java提供了Math类中的abs()方法,可以返回一个数的绝对值。使用该方法可以将负数转换为正数......